Browse Source

qcacmn: Fix kernel panic issue in mesh tx path

Add check for headroom before pushing the head for sufficient headroom
to prevent kernel panic in skb push function.

Change-Id: Iafc963f68b35564c7f291e9d91d933b3e31d7daa
CRs-Fixed: 2315569
Venkateswara Swamy Bandaru 6 years ago
parent
commit
41ebb3396b
3 changed files with 18 additions and 1 deletions
  1. 2 0
      dp/inc/cdp_txrx_stats_struct.h
  2. 3 0
      dp/wifi3.0/dp_main.c
  3. 13 1
      dp/wifi3.0/dp_tx.c

+ 2 - 0
dp/inc/cdp_txrx_stats_struct.h

@@ -491,6 +491,8 @@ struct cdp_tx_ingress_stats {
 		uint32_t enqueue_fail;
 		uint32_t dma_error;
 		uint32_t res_full;
+		/* headroom insufficient */
+		uint32_t headroom_insufficient;
 	} dropped;
 
 	/* Mesh packets info */

+ 3 - 0
dp/wifi3.0/dp_main.c

@@ -5503,6 +5503,7 @@ static inline void dp_aggregate_pdev_stats(struct dp_pdev *pdev)
 		DP_STATS_AGGR(pdev, vdev, tx_i.dropped.enqueue_fail);
 		DP_STATS_AGGR(pdev, vdev, tx_i.dropped.desc_na.num);
 		DP_STATS_AGGR(pdev, vdev, tx_i.dropped.res_full);
+		DP_STATS_AGGR(pdev, vdev, tx_i.dropped.headroom_insufficient);
 		DP_STATS_AGGR(pdev, vdev, tx_i.cce_classified);
 		DP_STATS_AGGR(pdev, vdev, tx_i.cce_classified_raw);
 		DP_STATS_AGGR(pdev, vdev, tx_i.mesh.exception_fw);
@@ -5683,6 +5684,8 @@ dp_print_pdev_tx_stats(struct dp_pdev *pdev)
 			pdev->stats.tx.dropped.fw_reason3);
 	DP_PRINT_STATS("	Aged Out from msdu/mpdu queues = %d",
 			pdev->stats.tx.dropped.age_out);
+	DP_PRINT_STATS("	headroom insufficient = %d",
+			pdev->stats.tx_i.dropped.headroom_insufficient);
 	DP_PRINT_STATS("	Multicast:");
 	DP_PRINT_STATS("	Packets: %u",
 		       pdev->stats.tx.mcast.num);

+ 13 - 1
dp/wifi3.0/dp_tx.c

@@ -274,7 +274,12 @@ static uint8_t dp_tx_prepare_htt_metadata(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 	htt_desc_size_aligned = (htt_desc_size + 7) & ~0x7;
 
 	if (vdev->mesh_vdev) {
-
+		if (qdf_unlikely(qdf_nbuf_headroom(nbuf) <
+					htt_desc_size_aligned)) {
+			DP_STATS_INC(vdev,
+				     tx_i.dropped.headroom_insufficient, 1);
+			return 0;
+		}
 		/* Fill and add HTT metaheader */
 		hdr = qdf_nbuf_push_head(nbuf, htt_desc_size_aligned);
 		if (hdr == NULL) {
@@ -665,6 +670,13 @@ struct dp_tx_desc_s *dp_tx_prepare_desc_single(struct dp_vdev *vdev,
 	if (qdf_unlikely((msdu_info->exception_fw)) ||
 				(vdev->opmode == wlan_op_mode_ocb)) {
 		align_pad = ((unsigned long) qdf_nbuf_data(nbuf)) & 0x7;
+
+		if (qdf_unlikely(qdf_nbuf_headroom(nbuf) < align_pad)) {
+			DP_STATS_INC(vdev,
+				     tx_i.dropped.headroom_insufficient, 1);
+			goto failure;
+		}
+
 		if (qdf_nbuf_push_head(nbuf, align_pad) == NULL) {
 			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
 					"qdf_nbuf_push_head failed");