OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | @@ -2131,6 +2131,9 @@ struct ieee80211_txq { |
||
27 | * @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't |
||
28 | * support QoS NDP for AP probing - that's most likely a driver bug. |
||
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 | @@ -2176,6 +2179,7 @@ enum ieee80211_hw_flags { |
||
37 | IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA, |
||
38 | IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, |
||
39 | IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP, |
||
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 | @@ -214,6 +214,7 @@ static const char *hw_flag_names[] = { |
||
47 | FLAG(SUPPORTS_TDLS_BUFFER_STA), |
||
48 | FLAG(DEAUTH_NEED_MGD_TX_PREP), |
||
49 | FLAG(DOESNT_SUPPORT_QOS_NDP), |
||
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 | @@ -1559,6 +1559,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 | @@ -301,7 +301,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 | @@ -655,9 +655,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 | @@ -1175,8 +1175,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 | @@ -2215,7 +2214,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 | @@ -2433,7 +2432,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 | @@ -2653,6 +2652,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 | @@ -2733,6 +2735,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 | @@ -2765,6 +2768,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 | @@ -2940,6 +2946,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 | @@ -3540,7 +3549,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 | @@ -1388,6 +1388,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 | @@ -1414,7 +1415,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); |