From 63705259d2cbba88d958e33b1e634c99acc1559b Mon Sep 17 00:00:00 2001 From: Jinwei Chen Date: Thu, 27 Jun 2019 17:12:03 +0800 Subject: [PATCH] qcacmn: fix dp_rx_defrag_add_last_frag peer tid array invalid access In some case, HW will fill in unexpected peer_id into RX PKT TLV, if this peer_id related peer is valid by coincidence, but actually this peer won't do dp_peer_rx_init(like SAP Vdev self peer), then invalid accessing to peer rx tid will happen. do SW WAR that add checking about peer tid array, if not initialed, free the rx nbuf. Change-Id: Icf196b4f92eb341e1ace5128c681d24c41dff6cd CRs-Fixed: 2468537 --- dp/wifi3.0/dp_rx_defrag.c | 18 +++++++++++++++++- dp/wifi3.0/dp_stats.c | 4 ++++ dp/wifi3.0/dp_types.h | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index 4f0abd966966..28033a42ae46 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -1702,7 +1702,7 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, QDF_STATUS dp_rx_defrag_add_last_frag(struct dp_soc *soc, struct dp_peer *peer, uint16_t tid, - uint16_t rxseq, qdf_nbuf_t nbuf) + uint16_t rxseq, qdf_nbuf_t nbuf) { struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; struct dp_rx_reorder_array_elem *rx_reorder_array_elem; @@ -1712,6 +1712,22 @@ QDF_STATUS dp_rx_defrag_add_last_frag(struct dp_soc *soc, rx_reorder_array_elem = peer->rx_tid[tid].array; + /* + * HW may fill in unexpected peer_id in RX PKT TLV, + * if this peer_id related peer is valid by coincidence, + * but actually this peer won't do dp_peer_rx_init(like SAP vdev + * self peer), then invalid access to rx_reorder_array_elem happened. + */ + if (!rx_reorder_array_elem) { + dp_verbose_debug( + "peer id:%d mac:" QDF_MAC_ADDR_STR "drop rx frame!", + peer->peer_ids[0], + QDF_MAC_ADDR_ARRAY(peer->mac_addr.raw)); + DP_STATS_INC(soc, rx.err.defrag_peer_uninit, 1); + qdf_nbuf_free(nbuf); + goto fail; + } + if (rx_reorder_array_elem->head && rxseq != rx_tid->curr_seq_num) { /* Drop stored fragments if out of sequence diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index b0d08c4d5cb7..1cdd2890a7ff 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -5096,6 +5096,8 @@ void dp_txrx_path_stats(struct dp_soc *soc) pdev->soc->stats.rx.err.rx_invalid_pkt_len.num); DP_PRINT_STATS("sa or da idx invalid %u", pdev->soc->stats.rx.err.invalid_sa_da_idx); + DP_PRINT_STATS("defrag peer uninit %u", + pdev->soc->stats.rx.err.defrag_peer_uninit); DP_PRINT_STATS("Reo Statistics"); DP_PRINT_STATS("rbm error: %u msdus", @@ -5556,6 +5558,8 @@ dp_print_soc_rx_stats(struct dp_soc *soc) soc->stats.rx.err.invalid_vdev); DP_PRINT_STATS("Invalid sa_idx or da_idx = %d", soc->stats.rx.err.invalid_sa_da_idx); + DP_PRINT_STATS("Defrag peer uninit = %d", + soc->stats.rx.err.defrag_peer_uninit); DP_PRINT_STATS("Invalid Pdev = %d", soc->stats.rx.err.invalid_pdev); DP_PRINT_STATS("Invalid Peer = %d", diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 7db72484296a..3889be023da4 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -690,6 +690,8 @@ struct dp_soc_stats { /* Invalid PDEV error count */ uint32_t invalid_pdev; + /* Defrag peer uninit error count */ + uint32_t defrag_peer_uninit; /* Invalid sa_idx or da_idx*/ uint32_t invalid_sa_da_idx; /* MSDU DONE failures */