diff options
| author | Rajeev Kumar <rajekuma@qca.qualcomm.com> | 2014-04-23 16:58:51 -0700 |
|---|---|---|
| committer | Akash Patel <c_akashp@qca.qualcomm.com> | 2014-04-26 00:48:15 -0700 |
| commit | ecc2eb4e135737e0f4633adc3c235b75c95ffbae (patch) | |
| tree | 1215774045de768c6bbefbc174a3185836ad8838 | |
| parent | 4b94121999b5bfddb4dc8d5d7eda8c65dee2dfa7 (diff) | |
qcacld: Fix race condition while deleting SAP peers
Fix race condition while accessing vdev->peer_list from
multiple contexts. Follwing is race condition in detail:
a. Kernel worker thread/MC thread which is processing VDEV
stop response from FW/VDEV response timeout calls
wma_delete_all_ap_remote_peers and try to delete all
remote peers.
b. wma_delete_all_ap_remote_peers access vdev->peer_list and
sends WMI peer delete command and after that FW sends
HTT_T2H_MSG_TYPE_PEER_UNMAP message to host. This message
is handled in wlan_tasklet context.
c. TXRX module while processing HTT_T2H_MSG_TYPE_PEER_UNMAP
also calls ol_txrx_peer_unref_delete to delete the peer
from vdev->peer_list.
d. Race condition is between b) and c) which can cause b) to
break from the FOR loop for peer_list even though it has
a pending peer.
Change-Id: I57a500dbac9018ab7641318714e219f1852f0bab
CRs-Fixed: 653359
| -rw-r--r-- | CORE/SERVICES/WMA/wma.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c index 6d9b64829a92..9d3bed430897 100644 --- a/CORE/SERVICES/WMA/wma.c +++ b/CORE/SERVICES/WMA/wma.c @@ -1003,14 +1003,18 @@ static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) return; /* remove all IBSS remote peers first */ + adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { if (peer != TAILQ_FIRST(&vdev->peer_list)) { + adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); adf_os_atomic_init(&peer->ref_cnt); adf_os_atomic_inc(&peer->ref_cnt); wma_remove_peer(wma, wma->interfaces[vdev_id].bssid, vdev_id, peer); + adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); } } + adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); /* remove IBSS bss peer last */ peer = TAILQ_FIRST(&vdev->peer_list); @@ -1020,26 +1024,31 @@ static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id) { - ol_txrx_vdev_handle vdev; - ol_txrx_peer_handle peer; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; - if (!wma || vdev_id > wma->max_bssid) - return; + if (!wma || vdev_id > wma->max_bssid) + return; - vdev = wma->interfaces[vdev_id].handle; - if (!vdev) - return; + vdev = wma->interfaces[vdev_id].handle; + if (!vdev) + return; - /* remove all remote peers of SAP */ - TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + /* remove all remote peers of SAP */ + adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { if (peer != TAILQ_FIRST(&vdev->peer_list)) { + adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); adf_os_atomic_init(&peer->ref_cnt); adf_os_atomic_inc(&peer->ref_cnt); wma_remove_peer(wma, peer->mac_addr.raw, vdev_id, peer); + adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); } } + adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); } + #ifdef QCA_IBSS_SUPPORT static void wma_recreate_ibss_vdev_and_bss_peer(tp_wma_handle wma, u_int8_t vdev_id) { |
