qcacld-3.0: Fix NULL pointer dereferencing of peer due to race condition
Peer get deleted during ol_txrx_peer_detach_force_delete when
WMA_ROAM_OFFLOAD_SYNCH_IND is received. As peer deletion is
happening in different context and ol_rx_send_pktlog_event is
accessing the peer in different context, a possible race condition
has occurred which leads to NULL pointer dereferencing of peer.
Ignore the peer deletion during ol_txrx_peer_detach_force_delete and
delete it during ol_rx_peer_unmap_handler.
Change-Id: Icf252612081a41f94db6df4684348f2962b2da9d
CRs-Fixed: 2238214
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index d076cff..47089b9 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -1342,6 +1342,7 @@
ol_txrx_tso_stats_init(pdev);
TAILQ_INIT(&pdev->vdev_list);
+ TAILQ_INIT(&pdev->roam_stale_peer_list);
TAILQ_INIT(&pdev->req_list);
pdev->req_list_depth = 0;
@@ -3460,6 +3461,36 @@
}
}
+bool ol_txrx_is_peer_eligible_for_deletion(ol_txrx_peer_handle peer)
+{
+ struct ol_txrx_vdev_t *vdev;
+ struct ol_txrx_pdev_t *pdev;
+ bool peerdel = true;
+ u_int16_t peer_id;
+ int i;
+
+ vdev = peer->vdev;
+ pdev = vdev->pdev;
+ for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) {
+ peer_id = peer->peer_ids[i];
+
+ if (!pdev->peer_id_to_obj_map[peer_id].peer_ref)
+ continue;
+
+ if (pdev->peer_id_to_obj_map[peer_id].peer_ref != peer)
+ continue;
+
+ if (qdf_atomic_read(&pdev->peer_id_to_obj_map[peer_id].
+ del_peer_id_ref_cnt)) {
+ peerdel = false;
+ break;
+ }
+
+ pdev->peer_id_to_obj_map[peer_id].peer_ref = NULL;
+ }
+ return peerdel;
+}
+
/**
* ol_txrx_peer_release_ref() - release peer reference
* @peer: peer handle
@@ -3657,7 +3688,31 @@
ol_txrx_dump_peer_access_list(peer);
- qdf_mem_free(peer);
+ qdf_spin_lock_bh(&pdev->peer_map_unmap_lock);
+ if (ol_txrx_is_peer_eligible_for_deletion(peer)) {
+ qdf_mem_free(peer);
+ } else {
+ /*
+ * Mark this PEER as a stale peer, to be deleted
+ * during PEER UNMAP. Remove this peer from
+ * roam_stale_peer_list during UNMAP.
+ */
+ struct ol_txrx_roam_stale_peer_t *roam_stale_peer;
+
+ roam_stale_peer = qdf_mem_malloc(
+ sizeof(struct ol_txrx_roam_stale_peer_t));
+ if (roam_stale_peer) {
+ roam_stale_peer->peer = peer;
+ TAILQ_INSERT_TAIL(&pdev->roam_stale_peer_list,
+ roam_stale_peer,
+ next_stale_entry);
+ } else {
+ QDF_TRACE(QDF_MODULE_ID_TXRX,
+ QDF_TRACE_LEVEL_ERROR,
+ "No memory allocated");
+ }
+ }
+ qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock);
} else {
access_list = qdf_atomic_read(
&peer->access_list[debug_id]);