qcacmn: Avoid using freed pdev in dp_rx_bar_stats_cb
dp_reo_cmdlist_destroy frees any pending reo_cmds.
Each reo_cmd is associated with a handler which takes
reo_cmd->data as an input. This reo_cmd->data is a pdev
for dp_rx_bar_stats_cb. So validate pdev before
accessing it further.
Change-Id: I1c2d46d3e3f5ede4491500978153f501ebdeee87
CRs-Fixed: 2478910
diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h
index cfbd311..9fabf18 100644
--- a/dp/wifi3.0/dp_internal.h
+++ b/dp/wifi3.0/dp_internal.h
@@ -862,6 +862,15 @@
#endif
/**
+ * dp_check_pdev_exists() - Validate pdev before use
+ * @soc - dp soc handle
+ * @data - pdev handle
+ *
+ * Return: 0 - success/invalid - failure
+ */
+bool dp_check_pdev_exists(struct dp_soc *soc, struct dp_pdev *data);
+
+/**
* dp_update_delay_stats() - Update delay statistics in structure
* and fill min, max and avg delay
* @pdev: pdev handle
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index 1559c85..5786285 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -6625,6 +6625,18 @@
}
#endif
+bool dp_check_pdev_exists(struct dp_soc *soc, struct dp_pdev *data)
+{
+ uint8_t pdev_count;
+
+ for (pdev_count = 0; pdev_count < MAX_PDEV_CNT; pdev_count++) {
+ if (soc->pdev_list[pdev_count] &&
+ soc->pdev_list[pdev_count] == data)
+ return true;
+ }
+ return false;
+}
+
/**
* dp_rx_bar_stats_cb(): BAR received stats callback
* @soc: SOC handle
@@ -6639,6 +6651,11 @@
struct dp_pdev *pdev = (struct dp_pdev *)cb_ctxt;
struct hal_reo_queue_status *queue_status = &(reo_status->queue_status);
+ if (!dp_check_pdev_exists(soc, pdev)) {
+ dp_err_rl("pdev doesn't exist");
+ return;
+ }
+
if (!qdf_atomic_read(&soc->cmn_init_done))
return;