瀏覽代碼

qcacld-3.0: Free skb if fisa flow vdev not matches dp_vdev

Currently, there is a rcu stall when dp vdev obtained from
dp_soc does not match vdev present in fisa flow which has
same vdev_id.
To fix this, if vdev id matches for both the vdev, drop the
skb.

Change-Id: I8be4ea77bd0bdd3096ebbad627674f7b8a9801cf
CRs-Fixed: 3817471
Ananya Gupta 1 年之前
父節點
當前提交
028bd45cbd
共有 2 個文件被更改,包括 41 次插入8 次删除
  1. 2 0
      components/dp/core/inc/wlan_dp_priv.h
  2. 39 8
      components/dp/core/src/wlan_dp_fisa_rx.c

+ 2 - 0
components/dp/core/inc/wlan_dp_priv.h

@@ -415,6 +415,7 @@ struct fisa_pkt_hist {
  * @rx_flow_tuple_info: RX tuple information
  * @napi_id: NAPI ID (REO ID) on which the flow is being received
  * @vdev: VDEV handle corresponding to the FLOW
+ * @vdev_id: DP vdev id
  * @dp_intf: DP interface handle corresponding to the flow
  * @bytes_aggregated: Number of bytes currently aggregated
  * @flush_count: Number of Flow flushes done
@@ -459,6 +460,7 @@ struct dp_fisa_rx_sw_ft {
 	struct cdp_rx_flow_tuple_info rx_flow_tuple_info;
 	uint8_t napi_id;
 	struct dp_vdev *vdev;
+	uint8_t vdev_id;
 	struct wlan_dp_intf *dp_intf;
 	uint64_t bytes_aggregated;
 	uint32_t flush_count;

+ 39 - 8
components/dp/core/src/wlan_dp_fisa_rx.c

@@ -459,6 +459,7 @@ static void dp_rx_fisa_update_sw_ft_entry(struct dp_fisa_rx_sw_ft *sw_ft_entry,
 {
 	sw_ft_entry->flow_hash = flow_hash;
 	sw_ft_entry->flow_id = flow_id;
+	sw_ft_entry->vdev_id = vdev->vdev_id;
 	sw_ft_entry->vdev = vdev;
 	sw_ft_entry->dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev);
 	sw_ft_entry->dp_ctx = dp_ctx;
@@ -590,6 +591,7 @@ dp_rx_fisa_add_ft_entry(struct dp_vdev *vdev,
 		if (is_same_flow(&sw_ft_entry->rx_flow_tuple_info,
 				 &rx_flow_tuple_info)) {
 			sw_ft_entry->vdev = vdev;
+			sw_ft_entry->vdev_id = vdev->vdev_id;
 			sw_ft_entry->dp_intf =
 					dp_fisa_rx_get_dp_intf_for_vdev(vdev);
 			dp_fisa_debug("It is same flow fse entry idx %d",
@@ -1131,6 +1133,7 @@ dp_fisa_rx_get_sw_ft_entry(struct dp_rx_fst *fisa_hdl, qdf_nbuf_t nbuf,
 
 	if (!fisa_hdl->flow_deletion_supported) {
 		sw_ft_entry->vdev = vdev;
+		sw_ft_entry->vdev_id = vdev->vdev_id;
 		sw_ft_entry->dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev);
 		return sw_ft_entry;
 	}
@@ -1145,6 +1148,7 @@ dp_fisa_rx_get_sw_ft_entry(struct dp_rx_fst *fisa_hdl, qdf_nbuf_t nbuf,
 		return NULL;
 
 	sw_ft_entry->vdev = vdev;
+	sw_ft_entry->vdev_id = vdev->vdev_id;
 	sw_ft_entry->dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev);
 	return sw_ft_entry;
 }
@@ -1478,6 +1482,7 @@ dp_fisa_rx_get_flow_flush_vdev_ref(ol_txrx_soc_handle cdp_soc,
 				   struct dp_fisa_rx_sw_ft *fisa_flow)
 {
 	struct dp_vdev *fisa_flow_head_skb_vdev;
+	struct dp_vdev *fisa_flow_vdev;
 	uint8_t vdev_id;
 
 	vdev_id = QDF_NBUF_CB_RX_VDEV_ID(fisa_flow->head_skb);
@@ -1492,21 +1497,30 @@ get_new_vdev_ref:
 	}
 
 	if (qdf_unlikely(fisa_flow_head_skb_vdev != fisa_flow->vdev)) {
+		if (qdf_unlikely(fisa_flow_head_skb_vdev->vdev_id ==
+				 fisa_flow->vdev_id))
+			goto fisa_flow_vdev_fail;
+
+		fisa_flow_vdev = dp_vdev_get_ref_by_id(
+						cdp_soc_t_to_dp_soc(cdp_soc),
+						fisa_flow->vdev_id,
+						DP_MOD_ID_RX);
+		if (qdf_unlikely(!fisa_flow_vdev))
+			goto fisa_flow_vdev_fail;
+
+		if (qdf_unlikely(fisa_flow_vdev != fisa_flow->vdev))
+			goto fisa_flow_vdev_mismatch;
+
 		/*
 		 * vdev_id may mismatch in case of MLO link switch.
 		 * Check if the vdevs belong to same MLD,
 		 * if yes, then submit the flow else drop the packets.
 		 */
 		if (qdf_unlikely(qdf_mem_cmp(
-				fisa_flow->vdev->mld_mac_addr.raw,
+				fisa_flow_vdev->mld_mac_addr.raw,
 				fisa_flow_head_skb_vdev->mld_mac_addr.raw,
 				QDF_MAC_ADDR_SIZE) != 0)) {
-			qdf_nbuf_free(fisa_flow->head_skb);
-			dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
-					     fisa_flow_head_skb_vdev,
-					     DP_MOD_ID_RX);
-			fisa_flow_head_skb_vdev = NULL;
-			goto out;
+			goto fisa_flow_vdev_mismatch;
 		} else {
 			fisa_flow->same_mld_vdev_mismatch++;
 			/* Continue with aggregation */
@@ -1515,15 +1529,32 @@ get_new_vdev_ref:
 			dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
 					     fisa_flow_head_skb_vdev,
 					     DP_MOD_ID_RX);
+
 			/*
 			 * Update vdev_id and let it loop to find this
 			 * vdev by ref.
 			 */
-			vdev_id = fisa_flow->vdev->vdev_id;
+			vdev_id = fisa_flow_vdev->vdev_id;
+			dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
+					     fisa_flow_vdev,
+					     DP_MOD_ID_RX);
 			goto get_new_vdev_ref;
 		}
+	} else {
+		goto out;
 	}
 
+fisa_flow_vdev_mismatch:
+	dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
+			     fisa_flow_vdev,
+			     DP_MOD_ID_RX);
+
+fisa_flow_vdev_fail:
+	qdf_nbuf_free(fisa_flow->head_skb);
+	dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
+			     fisa_flow_head_skb_vdev,
+			     DP_MOD_ID_RX);
+	fisa_flow_head_skb_vdev = NULL;
 out:
 	return fisa_flow_head_skb_vdev;
 }