Commit 9a5d353908db44d639108dee9fe05c0a8803b572
Committed by
Greg Kroah-Hartman
1 parent
79448960e3
Exists in
smarc_8mm_imx_4.14.98_2.0.0_ga
and in
6 other branches
mac80211: avoid kernel panic when building AMSDU from non-linear SKB
[ Upstream commit 166ac9d55b0ab70b644e429be1f217fe8393cbd7 ] When building building AMSDU from non-linear SKB, we hit a kernel panic when trying to push the padding to the tail. Instead, put the padding at the head of the next subframe. This also fixes the A-MSDU subframes to not have the padding accounted in the length field and not have pad at all for the last subframe, both required by the spec. Fixes: 6e0456b54545 ("mac80211: add A-MSDU tx support") Signed-off-by: Sara Sharon <sara.sharon@intel.com> Reviewed-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 21 additions and 17 deletions Side-by-side Diff
net/mac80211/tx.c
... | ... | @@ -3022,27 +3022,18 @@ |
3022 | 3022 | } |
3023 | 3023 | |
3024 | 3024 | static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, |
3025 | - struct sk_buff *skb, int headroom, | |
3026 | - int *subframe_len) | |
3025 | + struct sk_buff *skb, int headroom) | |
3027 | 3026 | { |
3028 | - int amsdu_len = *subframe_len + sizeof(struct ethhdr); | |
3029 | - int padding = (4 - amsdu_len) & 3; | |
3030 | - | |
3031 | - if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) { | |
3027 | + if (skb_headroom(skb) < headroom) { | |
3032 | 3028 | I802_DEBUG_INC(local->tx_expand_skb_head); |
3033 | 3029 | |
3034 | - if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) { | |
3030 | + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { | |
3035 | 3031 | wiphy_debug(local->hw.wiphy, |
3036 | 3032 | "failed to reallocate TX buffer\n"); |
3037 | 3033 | return false; |
3038 | 3034 | } |
3039 | 3035 | } |
3040 | 3036 | |
3041 | - if (padding) { | |
3042 | - *subframe_len += padding; | |
3043 | - skb_put_zero(skb, padding); | |
3044 | - } | |
3045 | - | |
3046 | 3037 | return true; |
3047 | 3038 | } |
3048 | 3039 | |
... | ... | @@ -3066,8 +3057,7 @@ |
3066 | 3057 | if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) |
3067 | 3058 | return true; |
3068 | 3059 | |
3069 | - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr), | |
3070 | - &subframe_len)) | |
3060 | + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr))) | |
3071 | 3061 | return false; |
3072 | 3062 | |
3073 | 3063 | data = skb_push(skb, sizeof(*amsdu_hdr)); |
... | ... | @@ -3133,7 +3123,8 @@ |
3133 | 3123 | void *data; |
3134 | 3124 | bool ret = false; |
3135 | 3125 | unsigned int orig_len; |
3136 | - int n = 1, nfrags; | |
3126 | + int n = 1, nfrags, pad = 0; | |
3127 | + u16 hdrlen; | |
3137 | 3128 | |
3138 | 3129 | if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) |
3139 | 3130 | return false; |
... | ... | @@ -3184,8 +3175,19 @@ |
3184 | 3175 | if (max_frags && nfrags > max_frags) |
3185 | 3176 | goto out; |
3186 | 3177 | |
3187 | - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2, | |
3188 | - &subframe_len)) | |
3178 | + /* | |
3179 | + * Pad out the previous subframe to a multiple of 4 by adding the | |
3180 | + * padding to the next one, that's being added. Note that head->len | |
3181 | + * is the length of the full A-MSDU, but that works since each time | |
3182 | + * we add a new subframe we pad out the previous one to a multiple | |
3183 | + * of 4 and thus it no longer matters in the next round. | |
3184 | + */ | |
3185 | + hdrlen = fast_tx->hdr_len - sizeof(rfc1042_header); | |
3186 | + if ((head->len - hdrlen) & 3) | |
3187 | + pad = 4 - ((head->len - hdrlen) & 3); | |
3188 | + | |
3189 | + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + | |
3190 | + 2 + pad)) | |
3189 | 3191 | goto out; |
3190 | 3192 | |
3191 | 3193 | ret = true; |
... | ... | @@ -3196,6 +3198,8 @@ |
3196 | 3198 | len = cpu_to_be16(subframe_len); |
3197 | 3199 | memcpy(data, &len, 2); |
3198 | 3200 | memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); |
3201 | + | |
3202 | + memset(skb_push(skb, pad), 0, pad); | |
3199 | 3203 | |
3200 | 3204 | head->len += skb->len; |
3201 | 3205 | head->data_len += skb->len; |