From 0843438590d7d7b669bdfa5c98dd706212d0ddba Mon Sep 17 00:00:00 2001 From: Shashikala Prabhu Date: Tue, 16 Jul 2019 15:42:03 +0530 Subject: [PATCH] qcacmn: Use correct skb headroom size to update radiotap header Size of rx_pkt_hdr tlv structure is used to check if there is enough space in the SKB to add radiotap header. The issue is seen due to a single SKB can hold the multiple TLVs and the next subsequent SKB has the data. In this case, there is no headroom available in the second SKB. Therefore crash seen while adding the radiotap header in the second SKB. To fix this issue, check if the SKB has enough headroom space. If not, drop the frame. Change-Id: Icd11f946c0aee974dde2ef21f59cfe3d8b87fa5d CRs-Fixed: 2480719 --- dp/inc/cdp_txrx_stats_struct.h | 5 ++++- dp/wifi3.0/dp_rx_mon_dest.c | 17 +++++++++++++---- dp/wifi3.0/dp_rx_mon_status.c | 8 ++++++-- dp/wifi3.0/dp_stats.c | 2 ++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h index 7f72301fff..aebaad0a7f 100644 --- a/dp/inc/cdp_txrx_stats_struct.h +++ b/dp/inc/cdp_txrx_stats_struct.h @@ -1198,6 +1198,7 @@ struct cdp_htt_rx_pdev_stats { * @mesh_filter: Mesh Filtered packets * @mon_rx_drop: packets dropped on monitor vap * @wifi_parse: rxdma errors due to wifi parse error + * @mon_radiotap_update_err: not enough space to update radiotap * @pkts: total packets replenished * @rxdma_err: rxdma errors for replenished * @nbuf_alloc_fail: nbuf alloc failed @@ -1227,8 +1228,10 @@ struct cdp_pdev_stats { uint32_t msdu_not_done; uint32_t mec; uint32_t mesh_filter; - uint32_t mon_rx_drop; uint32_t wifi_parse; + /* Monitor mode related */ + uint32_t mon_rx_drop; + uint32_t mon_radiotap_update_err; } dropped; struct { diff --git a/dp/wifi3.0/dp_rx_mon_dest.c b/dp/wifi3.0/dp_rx_mon_dest.c index 832b4f6082..2cb22f9ad3 100644 --- a/dp/wifi3.0/dp_rx_mon_dest.c +++ b/dp/wifi3.0/dp_rx_mon_dest.c @@ -963,8 +963,13 @@ QDF_STATUS dp_rx_mon_deliver(struct dp_soc *soc, uint32_t mac_id, if (pdev->ppdu_info.rx_status.chan_num == 0) pdev->ppdu_info.rx_status.chan_num = pdev->mon_chan_num; - qdf_nbuf_update_radiotap(&(pdev->ppdu_info.rx_status), - mon_mpdu, sizeof(struct rx_pkt_tlvs)); + if (!qdf_nbuf_update_radiotap(&pdev->ppdu_info.rx_status, + mon_mpdu, + qdf_nbuf_headroom(mon_mpdu))) { + DP_STATS_INC(pdev, dropped.mon_radiotap_update_err, 1); + goto mon_deliver_fail; + } + pdev->monitor_vdev->osif_rx_mon(pdev->monitor_vdev->osif_vdev, mon_mpdu, &pdev->ppdu_info.rx_status); @@ -1029,8 +1034,12 @@ QDF_STATUS dp_rx_mon_deliver_non_std(struct dp_soc *soc, pdev->ppdu_info.com_info.ppdu_id; /* Apply the radio header to this dummy skb */ - qdf_nbuf_update_radiotap(&pdev->ppdu_info.rx_status, - dummy_msdu, MAX_MONITOR_HEADER); + if (!qdf_nbuf_update_radiotap(&pdev->ppdu_info.rx_status, dummy_msdu, + qdf_nbuf_headroom(dummy_msdu))) { + DP_STATS_INC(pdev, dropped.mon_radiotap_update_err, 1); + qdf_nbuf_free(dummy_msdu); + goto mon_deliver_non_std_fail; + } /* deliver to the user layer application */ osif_rx_mon(pdev->monitor_vdev->osif_vdev, diff --git a/dp/wifi3.0/dp_rx_mon_status.c b/dp/wifi3.0/dp_rx_mon_status.c index 2c58d11b86..d8b733d03b 100644 --- a/dp/wifi3.0/dp_rx_mon_status.c +++ b/dp/wifi3.0/dp_rx_mon_status.c @@ -509,8 +509,12 @@ dp_rx_handle_smart_mesh_mode(struct dp_soc *soc, struct dp_pdev *pdev, /* Only retain RX MSDU payload in the skb */ qdf_nbuf_trim_tail(nbuf, qdf_nbuf_len(nbuf) - ppdu_info->msdu_info.payload_len); - qdf_nbuf_update_radiotap(&(pdev->ppdu_info.rx_status), - nbuf, sizeof(struct rx_pkt_tlvs)); + if (!qdf_nbuf_update_radiotap(&pdev->ppdu_info.rx_status, nbuf, + qdf_nbuf_headroom(nbuf))) { + DP_STATS_INC(pdev, dropped.mon_radiotap_update_err, 1); + return 1; + } + pdev->monitor_vdev->osif_rx_mon(pdev->monitor_vdev->osif_vdev, nbuf, NULL); pdev->ppdu_info.rx_status.monitor_direct_used = 0; diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index 39f27fd7bd..c291530a0c 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -5380,6 +5380,8 @@ dp_print_pdev_rx_stats(struct dp_pdev *pdev) pdev->stats.dropped.wifi_parse); DP_PRINT_STATS(" mon_rx_drop = %d", pdev->stats.dropped.mon_rx_drop); + DP_PRINT_STATS(" mon_radiotap_update_err = %d", + pdev->stats.dropped.mon_radiotap_update_err); DP_PRINT_STATS(" mec_drop = %d", pdev->stats.rx.mec_drop.num); DP_PRINT_STATS(" Bytes = %llu",