mac80211: update to version based on 4.19-rc4
[openwrt/staging/wigyori.git] / package / kernel / mac80211 / patches / 384-mac80211-avoid-kernel-panic-when-building-AMSDU-from.patch
1 From: Sara Sharon <sara.sharon@intel.com>
2 Date: Wed, 29 Aug 2018 08:57:02 +0200
3 Subject: [PATCH] mac80211: avoid kernel panic when building AMSDU from
4 non-linear SKB
5
6 When building building AMSDU from non-linear SKB, we hit a
7 kernel panic when trying to push the padding to the tail.
8 Instead, put the padding at the head of the next subframe.
9 This also fixes the A-MSDU subframes to not have the padding
10 accounted in the length field and not have pad at all for
11 the last subframe, both required by the spec.
12
13 Fixes: 6e0456b54545 ("mac80211: add A-MSDU tx support")
14 Signed-off-by: Sara Sharon <sara.sharon@intel.com>
15 Reviewed-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
16 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
17 ---
18
19 --- a/net/mac80211/tx.c
20 +++ b/net/mac80211/tx.c
21 @@ -3064,27 +3064,18 @@ void ieee80211_clear_fast_xmit(struct st
22 }
23
24 static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local,
25 - struct sk_buff *skb, int headroom,
26 - int *subframe_len)
27 + struct sk_buff *skb, int headroom)
28 {
29 - int amsdu_len = *subframe_len + sizeof(struct ethhdr);
30 - int padding = (4 - amsdu_len) & 3;
31 -
32 - if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) {
33 + if (skb_headroom(skb) < headroom) {
34 I802_DEBUG_INC(local->tx_expand_skb_head);
35
36 - if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) {
37 + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
38 wiphy_debug(local->hw.wiphy,
39 "failed to reallocate TX buffer\n");
40 return false;
41 }
42 }
43
44 - if (padding) {
45 - *subframe_len += padding;
46 - skb_put_zero(skb, padding);
47 - }
48 -
49 return true;
50 }
51
52 @@ -3108,8 +3099,7 @@ static bool ieee80211_amsdu_prepare_head
53 if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
54 return true;
55
56 - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr),
57 - &subframe_len))
58 + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr)))
59 return false;
60
61 data = skb_push(skb, sizeof(*amsdu_hdr));
62 @@ -3176,7 +3166,8 @@ static bool ieee80211_amsdu_aggregate(st
63 void *data;
64 bool ret = false;
65 unsigned int orig_len;
66 - int n = 1, nfrags;
67 + int n = 1, nfrags, pad = 0;
68 + u16 hdrlen;
69
70 if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
71 return false;
72 @@ -3228,8 +3219,19 @@ static bool ieee80211_amsdu_aggregate(st
73 if (max_frags && nfrags > max_frags)
74 goto out;
75
76 - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2,
77 - &subframe_len))
78 + /*
79 + * Pad out the previous subframe to a multiple of 4 by adding the
80 + * padding to the next one, that's being added. Note that head->len
81 + * is the length of the full A-MSDU, but that works since each time
82 + * we add a new subframe we pad out the previous one to a multiple
83 + * of 4 and thus it no longer matters in the next round.
84 + */
85 + hdrlen = fast_tx->hdr_len - sizeof(rfc1042_header);
86 + if ((head->len - hdrlen) & 3)
87 + pad = 4 - ((head->len - hdrlen) & 3);
88 +
89 + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) +
90 + 2 + pad))
91 goto out;
92
93 ret = true;
94 @@ -3241,6 +3243,8 @@ static bool ieee80211_amsdu_aggregate(st
95 memcpy(data, &len, 2);
96 memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header));
97
98 + memset(skb_push(skb, pad), 0, pad);
99 +
100 head->len += skb->len;
101 head->data_len += skb->len;
102 *frag_tail = skb;