summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2018-04-08 12:33:31 +0300
committerLuca Coelho <luciano.coelho@intel.com>2018-05-30 09:33:36 +0300
commit0eac9abace1629c20420d9122d6edc80d292b0ec (patch)
treedeab89789db2dd9958a55fd2655f0882089c8732 /drivers/net/wireless
parent15c4e33030d172ac0d2a03ebbae4c3687a80ac7d (diff)
downloadlinux-0eac9abace1629c20420d9122d6edc80d292b0ec.tar.xz
iwlwifi: mvm: fix TSO with highly fragmented SKBs
Our hardware has a limited amount of buffer descriptors for each Tx packet. Because of that, there is a short piece of code that makes sure that that we don't push too many subframes in an A-MSDU because of subframes needs 2 buffer descriptors. This code also takes into account the number of fragment of the skb since we also need a buffer descriptor for each fragment in the skb. This piece of code though didn't check that the resulting number of subframes wasn't 0. A user reported that using NFS client, he could get skbs that are so fragmented that the code mentioned above returned 0 for the number of subframes making skb_gso_segment fail and subconsequently iwlwifi would WARN. Fix this by make sure that num_subframes is at least 1. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=199209 Fixes: a6d5e32f247c ("iwlwifi: mvm: send large SKBs to the transport") Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index df4c60496f72..0b7f98d00298 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -843,8 +843,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
* N * subf_len + (N - 1) * pad.
*/
num_subframes = (max_amsdu_len + pad) / (subf_len + pad);
- if (num_subframes > 1)
- *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
tcp_hdrlen(skb) + skb->data_len;
@@ -855,10 +853,12 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
* 1 more for each fragment
* 1 more for the potential data in the header
*/
- num_subframes =
- min_t(unsigned int, num_subframes,
- (mvm->trans->max_skb_frags - 1 -
- skb_shinfo(skb)->nr_frags) / 2);
+ if ((num_subframes * 2 + skb_shinfo(skb)->nr_frags + 1) >
+ mvm->trans->max_skb_frags)
+ num_subframes = 1;
+
+ if (num_subframes > 1)
+ *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
/* This skb fits in one single A-MSDU */
if (num_subframes * mss >= tcp_payload_len) {