Browse Source

qcacld-3.0: Fix invalid dp_vdev accessing during FST update

scenario:
(1) DP FST update node with dp_vdev A has been inserted into
DP FST update list, but FST update work has not been queued due
runtime PM or it has not been scheduled for long time.
(2) dp vdev A get deleted after disconnection, but DP FST node with
dp vdev A still exists in list.
(3) new connection established, DP FST update work get scheduled,
invalid accessing to stale dp vdev A in
dp_fisa_rx_get_dp_intf_for_vdev() and hit panic.

solution:
(1) re-queue DP FST update work when runtime PM resume.
(2) validate dp vdev in dp_fisa_rx_fst_update_work() before
using it.

Change-Id: I7073a9d744806c33ddb5a7cbe9f7960890511eec
CRs-Fixed: 3607437
Jinwei Chen 1 year ago
parent
commit
9a1879b2e2

+ 17 - 1
components/dp/core/src/wlan_dp_fisa_rx.c

@@ -913,6 +913,7 @@ void dp_fisa_rx_fst_update_work(void *arg)
 	struct dp_rx_fst *fisa_hdl = arg;
 	qdf_list_node_t *node;
 	hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc;
+	struct dp_vdev *vdev;
 
 	if (qdf_atomic_read(&fisa_hdl->pm_suspended)) {
 		dp_err_rl("WQ triggered during suspend stage, deferred update");
@@ -930,7 +931,21 @@ void dp_fisa_rx_fst_update_work(void *arg)
 	while (qdf_list_peek_front(&fisa_hdl->fst_update_list, &node) ==
 	       QDF_STATUS_SUCCESS) {
 		elem = (struct dp_fisa_rx_fst_update_elem *)node;
-		dp_fisa_rx_fst_update(fisa_hdl, elem);
+		vdev = dp_vdev_get_ref_by_id(fisa_hdl->soc_hdl,
+					     elem->vdev_id,
+					     DP_MOD_ID_RX);
+		/*
+		 * Update fst only if current dp_vdev fetched by vdev_id is
+		 * still valid and match with the original dp_vdev when fst
+		 * node is queued.
+		 */
+		if (vdev) {
+			if (vdev == elem->vdev)
+				dp_fisa_rx_fst_update(fisa_hdl, elem);
+
+			dp_vdev_unref_delete(fisa_hdl->soc_hdl, vdev,
+					     DP_MOD_ID_RX);
+		}
 		qdf_list_remove_front(&fisa_hdl->fst_update_list, &node);
 		qdf_mem_free(elem);
 	}
@@ -1043,6 +1058,7 @@ dp_fisa_rx_queue_fst_update_work(struct dp_rx_fst *fisa_hdl, uint32_t flow_idx,
 	elem->reo_id = QDF_NBUF_CB_RX_CTX_ID(nbuf);
 	elem->reo_dest_indication = reo_dest_indication;
 	elem->vdev = vdev;
+	elem->vdev_id = vdev->vdev_id;
 
 	qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock);
 	qdf_list_insert_back(&fisa_hdl->fst_update_list, &elem->node);

+ 1 - 0
components/dp/core/src/wlan_dp_fisa_rx.h

@@ -72,6 +72,7 @@ struct dp_fisa_rx_fst_update_elem {
 	qdf_list_node_t node;
 	struct cdp_rx_flow_tuple_info flow_tuple_info;
 	struct dp_vdev *vdev;
+	uint8_t vdev_id;
 	uint32_t flow_idx;
 	uint32_t reo_dest_indication;
 	bool is_tcp_flow;

+ 2 - 2
components/dp/core/src/wlan_dp_main.c

@@ -1988,7 +1988,7 @@ QDF_STATUS __wlan_dp_runtime_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id)
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	dp_rx_fst_update_pm_suspend_status(dp_ctx, true);
+	status = wlan_dp_fisa_suspend(dp_ctx);
 
 	return status;
 }
@@ -2003,7 +2003,7 @@ QDF_STATUS __wlan_dp_runtime_resume(ol_txrx_soc_handle soc, uint8_t pdev_id)
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	dp_rx_fst_update_pm_suspend_status(dp_ctx, false);
+	status = wlan_dp_fisa_resume(dp_ctx);
 
 	return status;
 }