qcacmn: fix RX desc is using but freed back to pool
Crash scenario: (1) frag data A is dropped and related RX desc A is replenished and reused, but pdev->free_list_tail is still pointed to RX desc A. (2) frag data B/C is coming, defrag fails then pdev->free_list_head will point to B-->C RX desc, but pdev->free_list_tail still point to A. (3) for defrag failing case, host only will replenish 1 RX buffer for current case, RX desc B is replenished, while C will be free back to RX desc pool. (4) dp_rx_add_desc_list_to_free_list will set RX desc A-->next = free_list, free_list point to C insted. (5) when step (1) RX desc A replenished buffer indicated to host by REO2Dst ring, RX desc A -->nbuf actually is pointed to another RX desc, invalid skb accessing will happen. Solution: a. reset tail pointer in dp_rx_add_desc_list_to_free_list at last. b. reset tail pointer same as head in dp_rx_add_to_free_desc_list if head->next is NULL. c. set correct rx_bufs number for replenish when dp_rx_defrag fails. Change-Id: Ib297baea3605a09dd7d85d1f5ceb95db48a2e1f1 CRs-Fixed: 2603676
Este commit está contenido en:
@@ -1578,7 +1578,7 @@ dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
||||
}
|
||||
} else {
|
||||
dp_rx_add_to_free_desc_list(head, tail, rx_desc);
|
||||
*rx_bfs = 1;
|
||||
(*rx_bfs)++;
|
||||
|
||||
/* Return the non-head link desc */
|
||||
if (ring_desc &&
|
||||
@@ -1619,7 +1619,7 @@ dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
||||
|
||||
dp_rx_add_to_free_desc_list(head, tail,
|
||||
peer->rx_tid[tid].head_frag_desc);
|
||||
*rx_bfs = 1;
|
||||
(*rx_bfs)++;
|
||||
|
||||
if (dp_rx_link_desc_return(soc,
|
||||
peer->rx_tid[tid].dst_ring_desc,
|
||||
@@ -1660,7 +1660,7 @@ discard_frag:
|
||||
QDF_STATUS_SUCCESS)
|
||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
|
||||
"%s: Failed to return link desc", __func__);
|
||||
*rx_bfs = 1;
|
||||
(*rx_bfs)++;
|
||||
|
||||
end:
|
||||
if (peer)
|
||||
@@ -1698,7 +1698,7 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc,
|
||||
uint32_t rx_bufs_used = 0;
|
||||
qdf_nbuf_t msdu = NULL;
|
||||
uint32_t tid;
|
||||
int rx_bfs = 0;
|
||||
uint32_t rx_bfs = 0;
|
||||
struct dp_pdev *pdev;
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
|
||||
@@ -1737,7 +1737,7 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc,
|
||||
tid, rx_desc, &rx_bfs);
|
||||
|
||||
if (rx_bfs)
|
||||
rx_bufs_used++;
|
||||
rx_bufs_used += rx_bfs;
|
||||
|
||||
if (!QDF_IS_STATUS_SUCCESS(status))
|
||||
dp_info_rl("Rx Defrag err seq#:0x%x msdu_count:%d flags:%d",
|
||||
|
Referencia en una nueva incidencia
Block a user