qcacmn: Increment skb users for TSO pkt before enqueue of first segment
TSO packet segments are enqueued to the HW individually. The skb users count is incremented for each additional segment, so that it is freed only when the TX completion for the last segment is received. Currently the skb users is incremented for the additional TSO segments after the previous segment has been enqueued to the HW. Due to this, there is a chance for the tx completion for the first TSO segment to be received even before the skb users is incremented to account for the remaining TSO segments, thereby leading to use-after-free scenarios. Fix this by incrementing the skb users for additional TSO segment before enqueueing the previous TSO segment to the HW. Change-Id: Idebc28719ba6f0223d5454e15c3cde349803816e CRs-Fixed: 2801777
This commit is contained in:
@@ -2166,6 +2166,30 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
|
||||
HTT_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* For frames with multiple segments (TSO, ME), jump to next
|
||||
* segment.
|
||||
*/
|
||||
if (msdu_info->frm_type == dp_tx_frm_tso) {
|
||||
if (msdu_info->u.tso_info.curr_seg->next) {
|
||||
msdu_info->u.tso_info.curr_seg =
|
||||
msdu_info->u.tso_info.curr_seg->next;
|
||||
|
||||
/*
|
||||
* If this is a jumbo nbuf, then increment the
|
||||
* number of nbuf users for each additional
|
||||
* segment of the msdu. This will ensure that
|
||||
* the skb is freed only after receiving tx
|
||||
* completion for all segments of an nbuf
|
||||
*/
|
||||
qdf_nbuf_inc_users(nbuf);
|
||||
|
||||
/* Check with MCL if this is needed */
|
||||
/* nbuf = msdu_info->u.tso_info.curr_seg->nbuf;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enqueue the Tx MSDU descriptor to HW for transmit
|
||||
*/
|
||||
@@ -2210,6 +2234,17 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* For TSO frames, the nbuf users increment done for
|
||||
* the current segment has to be reverted, since the
|
||||
* hw enqueue for this segment failed
|
||||
*/
|
||||
if (msdu_info->frm_type == dp_tx_frm_tso &&
|
||||
msdu_info->u.tso_info.curr_seg) {
|
||||
qdf_nbuf_free(nbuf);
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -2220,28 +2255,6 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
|
||||
* can be combined into 1
|
||||
*/
|
||||
|
||||
/*
|
||||
* For frames with multiple segments (TSO, ME), jump to next
|
||||
* segment.
|
||||
*/
|
||||
if (msdu_info->frm_type == dp_tx_frm_tso) {
|
||||
if (msdu_info->u.tso_info.curr_seg->next) {
|
||||
msdu_info->u.tso_info.curr_seg =
|
||||
msdu_info->u.tso_info.curr_seg->next;
|
||||
|
||||
/*
|
||||
* If this is a jumbo nbuf, then increment the number of
|
||||
* nbuf users for each additional segment of the msdu.
|
||||
* This will ensure that the skb is freed only after
|
||||
* receiving tx completion for all segments of an nbuf
|
||||
*/
|
||||
qdf_nbuf_inc_users(nbuf);
|
||||
|
||||
/* Check with MCL if this is needed */
|
||||
/* nbuf = msdu_info->u.tso_info.curr_seg->nbuf; */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For Multicast-Unicast converted packets,
|
||||
* each converted frame (for a client) is represented as
|
||||
|
Reference in New Issue
Block a user