From 41ebb3396bfd7c5be56f9fb9bad31dcd8a00afb2 Mon Sep 17 00:00:00 2001 From: Venkateswara Swamy Bandaru Date: Wed, 12 Sep 2018 18:25:29 +0530 Subject: [PATCH] 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 --- dp/inc/cdp_txrx_stats_struct.h | 2 ++ dp/wifi3.0/dp_main.c | 3 +++ dp/wifi3.0/dp_tx.c | 14 +++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h index 5816a5562aff..9db2b56dc347 100644 --- a/dp/inc/cdp_txrx_stats_struct.h +++ b/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 */ diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index e1e04a807791..0010d2e89742 100644 --- a/dp/wifi3.0/dp_main.c +++ b/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); diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index af5b95e441b9..0d17ac700bc4 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/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");