mac80211: reorder patches putting backports first
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 358-mac80211-add-NEED_ALIGNED4_SKBS-hw-flag.patch
1 From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
2 Date: Fri, 19 Feb 2016 11:01:50 +0100
3 Subject: [PATCH] mac80211: add NEED_ALIGNED4_SKBS hw flag
4
5 HW/driver should set NEED_ALIGNED4_SKBS flag in case
6 require aligned skbs to four-byte boundaries.
7 This affect only TX direction.
8
9 Padding is added after ieee80211_hdr, before IV/LLC.
10
11 Before we have to do memmove(hdrlen) twice in the
12 dirver. Once before we pass this to HW and next
13 in tx completion (to be sure monitor will report
14 this tx frame correctly).
15
16 With this patch we can skip this memmove() and save CPU.
17
18 Currently this was tested with ath9k, both hw/sw crypt for
19 wep/tkip/ccmp.
20
21 Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
22 ---
23
24 --- a/include/net/mac80211.h
25 +++ b/include/net/mac80211.h
26 @@ -2059,6 +2059,9 @@ struct ieee80211_txq {
27 * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on
28 * TDLS links.
29 *
30 + * @IEEE80211_HW_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
31 + * Padding will be added after ieee80211_hdr, before IV/LLC.
32 + *
33 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
34 */
35 enum ieee80211_hw_flags {
36 @@ -2102,6 +2105,7 @@ enum ieee80211_hw_flags {
37 IEEE80211_HW_REPORTS_LOW_ACK,
38 IEEE80211_HW_SUPPORTS_TX_FRAG,
39 IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
40 + IEEE80211_HW_NEEDS_ALIGNED4_SKBS,
41
42 /* keep last, obviously */
43 NUM_IEEE80211_HW_FLAGS
44 --- a/net/mac80211/debugfs.c
45 +++ b/net/mac80211/debugfs.c
46 @@ -212,6 +212,7 @@ static const char *hw_flag_names[] = {
47 FLAG(REPORTS_LOW_ACK),
48 FLAG(SUPPORTS_TX_FRAG),
49 FLAG(SUPPORTS_TDLS_BUFFER_STA),
50 + FLAG(NEEDS_ALIGNED4_SKBS),
51 #undef FLAG
52 };
53
54 --- a/net/mac80211/ieee80211_i.h
55 +++ b/net/mac80211/ieee80211_i.h
56 @@ -1548,6 +1548,29 @@ ieee80211_vif_get_num_mcast_if(struct ie
57 return -1;
58 }
59
60 +static inline unsigned int
61 +ieee80211_hdr_padsize(struct ieee80211_hw *hw, unsigned int hdrlen)
62 +{
63 + /*
64 + * While hdrlen is already aligned to two-byte boundaries,
65 + * simple check with & 2 will return correct padsize.
66 + */
67 + if (ieee80211_hw_check(hw, NEEDS_ALIGNED4_SKBS))
68 + return hdrlen & 2;
69 + return 0;
70 +}
71 +
72 +static inline unsigned int
73 +ieee80211_padded_hdrlen(struct ieee80211_hw *hw, __le16 fc)
74 +{
75 + unsigned int hdrlen;
76 +
77 + hdrlen = ieee80211_hdrlen(fc);
78 + hdrlen += ieee80211_hdr_padsize(hw, hdrlen);
79 +
80 + return hdrlen;
81 +}
82 +
83 u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
84 struct ieee80211_rx_status *status,
85 unsigned int mpdu_len,
86 --- a/net/mac80211/sta_info.h
87 +++ b/net/mac80211/sta_info.h
88 @@ -300,7 +300,7 @@ struct ieee80211_fast_tx {
89 u8 hdr_len;
90 u8 sa_offs, da_offs, pn_offs;
91 u8 band;
92 - u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
93 + u8 hdr[30 + 2 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
94 sizeof(rfc1042_header)] __aligned(2);
95
96 struct rcu_head rcu_head;
97 --- a/net/mac80211/status.c
98 +++ b/net/mac80211/status.c
99 @@ -642,9 +642,22 @@ void ieee80211_tx_monitor(struct ieee802
100 struct sk_buff *skb2;
101 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
102 struct ieee80211_sub_if_data *sdata;
103 + struct ieee80211_hdr *hdr = (void *)skb->data;
104 struct net_device *prev_dev = NULL;
105 + unsigned int hdrlen, padsize;
106 int rtap_len;
107
108 + /* Remove padding if was added */
109 + if (ieee80211_hw_check(&local->hw, NEEDS_ALIGNED4_SKBS)) {
110 + hdrlen = ieee80211_hdrlen(hdr->frame_control);
111 + padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
112 +
113 + if (padsize && skb->len > hdrlen + padsize) {
114 + memmove(skb->data + padsize, skb->data, hdrlen);
115 + skb_pull(skb, padsize);
116 + }
117 + }
118 +
119 /* send frame to monitor interfaces now */
120 rtap_len = ieee80211_tx_radiotap_len(info);
121 if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
122 --- a/net/mac80211/tkip.c
123 +++ b/net/mac80211/tkip.c
124 @@ -201,10 +201,12 @@ void ieee80211_get_tkip_p2k(struct ieee8
125 {
126 struct ieee80211_key *key = (struct ieee80211_key *)
127 container_of(keyconf, struct ieee80211_key, conf);
128 + struct ieee80211_hw *hw = &key->local->hw;
129 const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
130 struct tkip_ctx *ctx = &key->u.tkip.tx;
131 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
132 - const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
133 + const u8 *data = (u8 *)hdr + ieee80211_padded_hdrlen(hw,
134 + hdr->frame_control);
135 u32 iv32 = get_unaligned_le32(&data[4]);
136 u16 iv16 = data[2] | (data[0] << 8);
137
138 --- a/net/mac80211/tx.c
139 +++ b/net/mac80211/tx.c
140 @@ -1172,8 +1172,7 @@ ieee80211_tx_prepare(struct ieee80211_su
141 info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
142
143 hdr = (struct ieee80211_hdr *) skb->data;
144 -
145 - tx->hdrlen = ieee80211_hdrlen(hdr->frame_control);
146 + tx->hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
147
148 if (likely(sta)) {
149 if (!IS_ERR(sta))
150 @@ -2184,7 +2183,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
151 goto fail;
152
153 hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
154 - hdrlen = ieee80211_hdrlen(hdr->frame_control);
155 + hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
156
157 if (skb->len < len_rthdr + hdrlen)
158 goto fail;
159 @@ -2402,7 +2401,7 @@ static struct sk_buff *ieee80211_build_h
160 struct ieee80211_chanctx_conf *chanctx_conf;
161 struct ieee80211_sub_if_data *ap_sdata;
162 enum nl80211_band band;
163 - int ret;
164 + int padsize, ret;
165
166 if (IS_ERR(sta))
167 sta = NULL;
168 @@ -2622,6 +2621,9 @@ static struct sk_buff *ieee80211_build_h
169 hdrlen += 2;
170 }
171
172 + /* Check aligned4 skb required */
173 + padsize = ieee80211_hdr_padsize(&sdata->local->hw, hdrlen);
174 +
175 /*
176 * Drop unicast frames to unauthorised stations unless they are
177 * EAPOL frames from the local station.
178 @@ -2702,6 +2704,7 @@ static struct sk_buff *ieee80211_build_h
179
180 skb_pull(skb, skip_header_bytes);
181 head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
182 + head_need += padsize;
183
184 /*
185 * So we need to modify the skb header and hence need a copy of
186 @@ -2734,6 +2737,9 @@ static struct sk_buff *ieee80211_build_h
187 memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
188 #endif
189
190 + if (padsize)
191 + memset(skb_push(skb, padsize), 0, padsize);
192 +
193 if (ieee80211_is_data_qos(fc)) {
194 __le16 *qos_control;
195
196 @@ -2909,6 +2915,9 @@ void ieee80211_check_fast_xmit(struct st
197 fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
198 }
199
200 + /* Check aligned4 skb required */
201 + build.hdr_len += ieee80211_hdr_padsize(&local->hw, build.hdr_len);
202 +
203 /* We store the key here so there's no point in using rcu_dereference()
204 * but that's fine because the code that changes the pointers will call
205 * this function after doing so. For a single CPU that would be enough,
206 @@ -3495,7 +3504,7 @@ begin:
207
208 if (tx.key &&
209 (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
210 - pn_offs = ieee80211_hdrlen(hdr->frame_control);
211 + pn_offs = tx.hdrlen;
212
213 ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
214 tx.key, skb);
215 --- a/net/mac80211/util.c
216 +++ b/net/mac80211/util.c
217 @@ -1230,6 +1230,7 @@ void ieee80211_send_auth(struct ieee8021
218 u32 tx_flags)
219 {
220 struct ieee80211_local *local = sdata->local;
221 + struct ieee80211_hw *hw = &local->hw;
222 struct sk_buff *skb;
223 struct ieee80211_mgmt *mgmt;
224 unsigned int hdrlen;
225 @@ -1256,7 +1257,7 @@ void ieee80211_send_auth(struct ieee8021
226 skb_put_data(skb, extra, extra_len);
227
228 if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
229 - hdrlen = ieee80211_hdrlen(mgmt->frame_control);
230 + hdrlen = ieee80211_padded_hdrlen(hw, mgmt->frame_control);
231 mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
232 err = ieee80211_wep_encrypt(local, skb, hdrlen, key,
233 key_len, key_idx);