summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRajeev Kumar <rajekuma@qca.qualcomm.com>2014-02-07 14:52:41 -0800
committerAkash Patel <c_akashp@qca.qualcomm.com>2014-02-07 23:06:13 -0800
commitd5a9be97d752f4a885b7dd7c5cf2e7c873f5ba50 (patch)
tree160b6e0a6138b4feb5a22cfc4a6db6a131e3fb62
parent1905c73e2314c1d2fbf3942aa590fd0d603e1b19 (diff)
qcacld: Fixing crashes caused by dangling vdev pointer
wma_vdev_deatch() should not call ol_txrx_vdev_deatch() for same vdev object otherwise it can cause access of same vdev object which is already freed and crash because of that. Adding a wma_vdev_detach spin lock to protect ol_txrx_vdev_detach() getting called 2 or more times for same vdev from different threads. Change-Id: I005b388c188b0885516fc1d3bd2e9b2722627481 CRs-Fixed: 612606
-rw-r--r--CORE/SERVICES/WMA/wma.c70
-rw-r--r--CORE/SERVICES/WMA/wma.h1
2 files changed, 42 insertions, 29 deletions
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index 4041d65cda8c..3d04929b472e 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -2332,6 +2332,8 @@ VOS_STATUS WDA_open(v_VOID_t *vos_context, v_VOID_t *os_ctx,
INIT_LIST_HEAD(&wma_handle->vdev_resp_queue);
adf_os_spinlock_init(&wma_handle->vdev_respq_lock);
+ adf_os_spinlock_init(&wma_handle->vdev_detach_lock);
+
/* Register vdev start response event handler */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_VDEV_START_RESP_EVENTID,
@@ -2716,38 +2718,48 @@ static VOS_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
return status;
}
- /* remove the interface from ath_dev */
- if (wma_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id)) {
- WMA_LOGP("Unable to remove an interface for ath_dev.\n");
- status = VOS_STATUS_E_FAILURE;
- goto out;
- }
- if(!iface->handle) {
- status = VOS_STATUS_E_FAILURE;
- WMA_LOGP("handle of vdev_id %d is NULL", vdev_id);
- goto out;
- }
+ adf_os_spin_lock_bh(&wma_handle->vdev_detach_lock);
+ if(!iface->handle) {
+ status = VOS_STATUS_E_FAILURE;
+ WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed",
+ vdev_id);
+ adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
+ goto out;
+ }
- WMA_LOGA("vdev_id:%hu vdev_hdl:%p\n", vdev_id, iface->handle);
- if (!generateRsp) {
- WMA_LOGD("Call txrx detach w/o callback for vdev %d", vdev_id);
- ol_txrx_vdev_detach(iface->handle, NULL, NULL);
- goto out;
- }
+ /* remove the interface from ath_dev */
+ if (wma_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id)) {
+ WMA_LOGE("Unable to remove an interface for ath_dev.\n");
+ status = VOS_STATUS_E_FAILURE;
+ adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
+ goto out;
+ }
- iface->del_staself_req = pdel_sta_self_req_param;
- msg = wma_fill_vdev_req(wma_handle, vdev_id, WDA_DEL_STA_SELF_REQ,
- WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 2000);
- if (!msg) {
- WMA_LOGP("%s: Failed to fill vdev request for vdev_id %d\n",
- __func__, vdev_id);
- status = VOS_STATUS_E_NOMEM;
- goto out;
- }
- WMA_LOGD("Call txrx detach with callback for vdev %d", vdev_id);
- ol_txrx_vdev_detach(iface->handle, wma_vdev_detach_callback, iface);
- return status;
+
+ WMA_LOGA("vdev_id:%hu vdev_hdl:%p\n", vdev_id, iface->handle);
+ if (!generateRsp) {
+ WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id);
+ ol_txrx_vdev_detach(iface->handle, NULL, NULL);
+ adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
+ goto out;
+ }
+
+ iface->del_staself_req = pdel_sta_self_req_param;
+ msg = wma_fill_vdev_req(wma_handle, vdev_id, WDA_DEL_STA_SELF_REQ,
+ WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 2000);
+ if (!msg) {
+ WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d\n",
+ __func__, vdev_id);
+ status = VOS_STATUS_E_NOMEM;
+ adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
+ goto out;
+ }
+ WMA_LOGE("Call txrx detach with callback for vdev %d", vdev_id);
+ ol_txrx_vdev_detach(iface->handle, NULL, NULL);
+ wma_vdev_detach_callback(iface);
+ adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
+ return status;
out:
if(iface->addBssStaContext)
adf_os_mem_free(iface->addBssStaContext);
diff --git a/CORE/SERVICES/WMA/wma.h b/CORE/SERVICES/WMA/wma.h
index dc20ffbd4900..53501bc49003 100644
--- a/CORE/SERVICES/WMA/wma.h
+++ b/CORE/SERVICES/WMA/wma.h
@@ -521,6 +521,7 @@ typedef struct {
u_int32_t peer_count;
struct list_head vdev_resp_queue;
adf_os_spinlock_t vdev_respq_lock;
+ adf_os_spinlock_t vdev_detach_lock;
u_int32_t ht_cap_info;
#ifdef WLAN_FEATURE_11AC
u_int32_t vht_cap_info;