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
This commit is contained in:
Venkateswara Swamy Bandaru 2018-09-12 18:25:29 +05:30 • committed by nshrivas
commit 41ebb3396b
3 changed files with 18 additions and 1 deletions

View file

@ -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 */

View file

@ -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);

View file

@ -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");