mirror of https://gitee.com/openkylin/linux.git
ath10k: fix handling of wierd MSDU chaining cases
Apparently firmware can sometimes report a sequence with the first rx descriptor saying it's not the last MSDU. In that case msdu_chaining value could be overwritten saying it's not a chained MSDU. This in turn led to skb_push panic as the frame could be treated as an A-MSDU instead of a chained MSDU. Reported-By: Avery Pennarun <apenwarr@gmail.com> Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
3e841fd0a5
commit
ede9c8e091
|
@ -312,6 +312,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||||
int msdu_len, msdu_chaining = 0;
|
int msdu_len, msdu_chaining = 0;
|
||||||
struct sk_buff *msdu;
|
struct sk_buff *msdu;
|
||||||
struct htt_rx_desc *rx_desc;
|
struct htt_rx_desc *rx_desc;
|
||||||
|
bool corrupted = false;
|
||||||
|
|
||||||
lockdep_assert_held(&htt->rx_ring.lock);
|
lockdep_assert_held(&htt->rx_ring.lock);
|
||||||
|
|
||||||
|
@ -405,7 +406,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||||
msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0),
|
msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0),
|
||||||
RX_MSDU_START_INFO0_MSDU_LENGTH);
|
RX_MSDU_START_INFO0_MSDU_LENGTH);
|
||||||
msdu_chained = rx_desc->frag_info.ring2_more_count;
|
msdu_chained = rx_desc->frag_info.ring2_more_count;
|
||||||
msdu_chaining = msdu_chained;
|
|
||||||
|
|
||||||
if (msdu_len_invalid)
|
if (msdu_len_invalid)
|
||||||
msdu_len = 0;
|
msdu_len = 0;
|
||||||
|
@ -433,11 +433,15 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||||
|
|
||||||
msdu->next = next;
|
msdu->next = next;
|
||||||
msdu = next;
|
msdu = next;
|
||||||
|
msdu_chaining = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
|
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
|
||||||
RX_MSDU_END_INFO0_LAST_MSDU;
|
RX_MSDU_END_INFO0_LAST_MSDU;
|
||||||
|
|
||||||
|
if (msdu_chaining && !last_msdu)
|
||||||
|
corrupted = true;
|
||||||
|
|
||||||
if (last_msdu) {
|
if (last_msdu) {
|
||||||
msdu->next = NULL;
|
msdu->next = NULL;
|
||||||
break;
|
break;
|
||||||
|
@ -452,6 +456,20 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||||
if (*head_msdu == NULL)
|
if (*head_msdu == NULL)
|
||||||
msdu_chaining = -1;
|
msdu_chaining = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apparently FW sometimes reports weird chained MSDU sequences with
|
||||||
|
* more than one rx descriptor. This seems like a bug but needs more
|
||||||
|
* analyzing. For the time being fix it by dropping such sequences to
|
||||||
|
* avoid blowing up the host system.
|
||||||
|
*/
|
||||||
|
if (corrupted) {
|
||||||
|
ath10k_warn("failed to pop chained msdus, dropping\n");
|
||||||
|
ath10k_htt_rx_free_msdu_chain(*head_msdu);
|
||||||
|
*head_msdu = NULL;
|
||||||
|
*tail_msdu = NULL;
|
||||||
|
msdu_chaining = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't refill the ring yet.
|
* Don't refill the ring yet.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue