From aab74f76ee5286ec30c4ca58fe948ff45cc3bb87 Mon Sep 17 00:00:00 2001 From: Ananya Gupta Date: Thu, 18 Jun 2020 11:47:46 +0530 Subject: [PATCH] qcacmn: Check peer before accessing vdev in tx_comp_handler Race Condition is observed as tx_comp_handler is accessing vdev pointer while its getting freed up parallelly. To fix this, peer value is checked before accessing vdev. If peer is null, vdev is not accessed and the function is returned. Change-Id: I05c93c54e2dbb3f40c5c053591d2d66c6143f656 CRs-Fixed: 2708390 --- dp/wifi3.0/dp_tx.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 15a490ae46..aab1544ca1 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -3411,6 +3411,7 @@ void dp_tx_update_connectivity_stats(struct dp_soc *soc, /** * dp_tx_comp_process_tx_status() - Parse and Dump Tx completion status info + * @soc: DP soc handle * @tx_desc: software descriptor head pointer * @ts: Tx completion status * @peer: peer handle @@ -3419,13 +3420,13 @@ void dp_tx_update_connectivity_stats(struct dp_soc *soc, * Return: none */ static inline -void dp_tx_comp_process_tx_status(struct dp_tx_desc_s *tx_desc, +void dp_tx_comp_process_tx_status(struct dp_soc *soc, + struct dp_tx_desc_s *tx_desc, struct hal_tx_completion_status *ts, struct dp_peer *peer, uint8_t ring_id) { uint32_t length; qdf_ether_header_t *eh; - struct dp_soc *soc = NULL; struct dp_vdev *vdev = tx_desc->vdev; qdf_nbuf_t nbuf = tx_desc->nbuf; uint8_t dp_status; @@ -3436,6 +3437,7 @@ void dp_tx_comp_process_tx_status(struct dp_tx_desc_s *tx_desc, } eh = (qdf_ether_header_t *)qdf_nbuf_data(nbuf); + length = qdf_nbuf_len(nbuf); dp_status = qdf_dp_get_status_from_htt(ts->status); DPTRACE(qdf_dp_trace_ptr(tx_desc->nbuf, @@ -3475,28 +3477,24 @@ void dp_tx_comp_process_tx_status(struct dp_tx_desc_s *tx_desc, ts->tones_in_ru, ts->tsf, ts->ppdu_id, ts->transmit_cnt, ts->tid, ts->peer_id); - soc = vdev->pdev->soc; - - dp_tx_update_connectivity_stats(soc, tx_desc, ts->status); - /* Update SoC level stats */ DP_STATS_INCC(soc, tx.dropped_fw_removed, 1, (ts->status == HAL_TX_TQM_RR_REM_CMD_REM)); + if (!peer) { + dp_err_rl("peer is null or deletion in progress"); + DP_STATS_INC_PKT(soc, tx.tx_invalid_peer, 1, length); + goto out; + } + + dp_tx_update_connectivity_stats(soc, tx_desc, ts->status); + /* Update per-packet stats for mesh mode */ if (qdf_unlikely(vdev->mesh_vdev) && !(tx_desc->flags & DP_TX_DESC_FLAG_TO_FW)) dp_tx_comp_fill_tx_completion_stats(tx_desc, ts); - length = qdf_nbuf_len(nbuf); /* Update peer level stats */ - if (!peer) { - QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_DP, - "peer is null or deletion in progress"); - DP_STATS_INC_PKT(soc, tx.tx_invalid_peer, 1, length); - goto out; - } - if (qdf_unlikely(peer->bss_peer && vdev->opmode == wlan_op_mode_ap)) { if (ts->status != HAL_TX_TQM_RR_REM_CMD_REM) { DP_STATS_INC_PKT(peer, tx.mcast, 1, length); @@ -3587,7 +3585,7 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc, } hal_tx_comp_get_status(&desc->comp, &ts, soc->hal_soc); peer = dp_peer_find_by_id(soc, ts.peer_id); - dp_tx_comp_process_tx_status(desc, &ts, peer, ring_id); + dp_tx_comp_process_tx_status(soc, desc, &ts, peer, ring_id); netbuf = desc->nbuf; /* check tx complete notification */ @@ -3710,7 +3708,7 @@ void dp_tx_process_htt_completion(struct dp_tx_desc_s *tx_desc, uint8_t *status, if (qdf_likely(peer)) dp_peer_unref_del_find_by_id(peer); - dp_tx_comp_process_tx_status(tx_desc, &ts, peer, ring_id); + dp_tx_comp_process_tx_status(soc, tx_desc, &ts, peer, ring_id); dp_tx_comp_process_desc(soc, tx_desc, &ts, peer); dp_tx_desc_release(tx_desc, tx_desc->pool_id);