aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2009-08-29 14:30:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-31 14:42:14 -0400
commitdaee6c092aa49ea090612738253ef0d11d120344 (patch)
tree97ab49a8a465b2e0fa470a6e9c5f0264e5db94d3 /drivers
parent2e27cff871dec9371e41022aaaebb3452ec069c0 (diff)
rt2x00: Reorganize padding & L2 padding
The old function rt2x00queue_payload_align() handled both adding and removing L2 padding and some basic frame alignment. The entire function was being abused because it had multiple functions and the header length argument was somtimes used to align the header instead of the payload. Additionally there was a bug when inserting L2 padding that only the payload was aligned but not the header. This happens when the header wasn't aligned properly by mac80211, but rt2x00lib only moves the payload. A secondary problem was that when removing L2 padding during TXdone or RX the skb wasn't resized to the proper size. Split the function into seperate functions each handling its task as it should. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h45
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c99
4 files changed, 116 insertions, 44 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 30fbd3bbe08b..de36837dcf86 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -154,7 +154,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
154 skbdesc->flags &= ~SKBDESC_IV_STRIPPED; 154 skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
155} 155}
156 156
157void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, 157void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
158 unsigned int header_length, 158 unsigned int header_length,
159 struct rxdone_entry_desc *rxdesc) 159 struct rxdone_entry_desc *rxdesc)
160{ 160{
@@ -199,7 +199,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
199 * move the header more then iv_len since we must 199 * move the header more then iv_len since we must
200 * make room for the payload move as well. 200 * make room for the payload move as well.
201 */ 201 */
202 if (l2pad) { 202 if (rxdesc->dev_flags & RXDONE_L2PAD) {
203 skb_push(skb, iv_len - align); 203 skb_push(skb, iv_len - align);
204 skb_put(skb, icv_len); 204 skb_put(skb, icv_len);
205 205
@@ -230,7 +230,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
230 * Move payload for alignment purposes. Note that 230 * Move payload for alignment purposes. Note that
231 * this is only needed when no l2 padding is present. 231 * this is only needed when no l2 padding is present.
232 */ 232 */
233 if (!l2pad) { 233 if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
234 memmove(skb->data + transfer, 234 memmove(skb->data + transfer,
235 skb->data + transfer + align, 235 skb->data + transfer + align,
236 payload_len); 236 payload_len);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 0647e514dde1..71761b343839 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -217,7 +217,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
217 * Remove L2 padding which was added during 217 * Remove L2 padding which was added during
218 */ 218 */
219 if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) 219 if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
220 rt2x00queue_payload_align(entry->skb, true, header_length); 220 rt2x00queue_remove_l2pad(entry->skb, header_length);
221 221
222 /* 222 /*
223 * If the IV/EIV data was stripped from the frame before it was 223 * If the IV/EIV data was stripped from the frame before it was
@@ -364,7 +364,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
364 struct sk_buff *skb; 364 struct sk_buff *skb;
365 struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; 365 struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
366 unsigned int header_length; 366 unsigned int header_length;
367 bool l2pad;
368 int rate_idx; 367 int rate_idx;
369 /* 368 /*
370 * Allocate a new sk_buffer. If no new buffer available, drop the 369 * Allocate a new sk_buffer. If no new buffer available, drop the
@@ -393,7 +392,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
393 * aligned on a 4 byte boundary. 392 * aligned on a 4 byte boundary.
394 */ 393 */
395 header_length = ieee80211_get_hdrlen_from_skb(entry->skb); 394 header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
396 l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD);
397 395
398 /* 396 /*
399 * Hardware might have stripped the IV/EIV/ICV data, 397 * Hardware might have stripped the IV/EIV/ICV data,
@@ -403,10 +401,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
403 */ 401 */
404 if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && 402 if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
405 (rxdesc.flags & RX_FLAG_IV_STRIPPED)) 403 (rxdesc.flags & RX_FLAG_IV_STRIPPED))
406 rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length, 404 rt2x00crypto_rx_insert_iv(entry->skb, header_length,
407 &rxdesc); 405 &rxdesc);
406 else if (rxdesc.dev_flags & RXDONE_L2PAD)
407 rt2x00queue_remove_l2pad(entry->skb, header_length);
408 else 408 else
409 rt2x00queue_payload_align(entry->skb, l2pad, header_length); 409 rt2x00queue_align_payload(entry->skb, header_length);
410 410
411 /* 411 /*
412 * Check if the frame was received using HT. In that case, 412 * Check if the frame was received using HT. In that case,
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index eeb2881e818e..5462cb5ad994 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -120,21 +120,42 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
120void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); 120void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
121 121
122/** 122/**
123 * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary 123 * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary
124 * @skb: The skb to align
125 *
126 * Align the start of the 802.11 frame to a 4-byte boundary, this could
127 * mean the payload is not aligned properly though.
128 */
129void rt2x00queue_align_frame(struct sk_buff *skb);
130
131/**
132 * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
133 * @skb: The skb to align
134 * @header_length: Length of 802.11 header
135 *
136 * Align the 802.11 payload to a 4-byte boundary, this could
137 * mean the header is not aligned properly though.
138 */
139void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length);
140
141/**
142 * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
143 * @skb: The skb to align
144 * @header_length: Length of 802.11 header
145 *
146 * Apply L2 padding to align both header and payload to 4-byte boundary
147 */
148void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length);
149
150/**
151 * rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame
124 * @skb: The skb to align 152 * @skb: The skb to align
125 * @l2pad: Should L2 padding be used
126 * @header_length: Length of 802.11 header 153 * @header_length: Length of 802.11 header
127 * 154 *
128 * This function prepares the @skb to be send to the device or mac80211. 155 * Remove L2 padding used to align both header and payload to 4-byte boundary,
129 * If @l2pad is set to true padding will occur between the 802.11 header 156 * by removing the L2 padding the header will no longer be 4-byte aligned.
130 * and payload. Otherwise the padding will be done in front of the 802.11
131 * header.
132 * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED
133 * flag in &skb_frame_desc. If that flag is set, the padding is removed
134 * and the flag cleared. Otherwise the padding is added and the flag is set.
135 */ 157 */
136void rt2x00queue_payload_align(struct sk_buff *skb, 158void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
137 bool l2pad, unsigned int header_length);
138 159
139/** 160/**
140 * rt2x00queue_write_tx_frame - Write TX frame to hardware 161 * rt2x00queue_write_tx_frame - Write TX frame to hardware
@@ -324,7 +345,7 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
324void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, 345void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
325 struct txentry_desc *txdesc); 346 struct txentry_desc *txdesc);
326void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length); 347void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length);
327void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, 348void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
328 unsigned int header_length, 349 unsigned int header_length,
329 struct rxdone_entry_desc *rxdesc); 350 struct rxdone_entry_desc *rxdesc);
330#else 351#else
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 06af823efd83..577029efe320 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -148,35 +148,89 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
148 dev_kfree_skb_any(skb); 148 dev_kfree_skb_any(skb);
149} 149}
150 150
151void rt2x00queue_payload_align(struct sk_buff *skb, 151void rt2x00queue_align_frame(struct sk_buff *skb)
152 bool l2pad, unsigned int header_length)
153{ 152{
154 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
155 unsigned int frame_length = skb->len; 153 unsigned int frame_length = skb->len;
156 unsigned int align = ALIGN_SIZE(skb, header_length); 154 unsigned int align = ALIGN_SIZE(skb, 0);
157 155
158 if (!align) 156 if (!align)
159 return; 157 return;
160 158
161 if (l2pad) { 159 skb_push(skb, align);
162 if (skbdesc->flags & SKBDESC_L2_PADDED) { 160 memmove(skb->data, skb->data + align, frame_length);
163 /* Remove L2 padding */ 161 skb_trim(skb, frame_length);
164 memmove(skb->data + align, skb->data, header_length); 162}
165 skb_pull(skb, align); 163
166 skbdesc->flags &= ~SKBDESC_L2_PADDED; 164void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt)
167 } else { 165{
168 /* Add L2 padding */ 166 unsigned int frame_length = skb->len;
169 skb_push(skb, align); 167 unsigned int align = ALIGN_SIZE(skb, header_lengt);
170 memmove(skb->data, skb->data + align, header_length); 168
171 skbdesc->flags |= SKBDESC_L2_PADDED; 169 if (!align)
172 } 170 return;
171
172 skb_push(skb, align);
173 memmove(skb->data, skb->data + align, frame_length);
174 skb_trim(skb, frame_length);
175}
176
177void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
178{
179 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
180 unsigned int frame_length = skb->len;
181 unsigned int header_align = ALIGN_SIZE(skb, 0);
182 unsigned int payload_align = ALIGN_SIZE(skb, header_length);
183 unsigned int l2pad = 4 - (payload_align - header_align);
184
185 if (header_align == payload_align) {
186 /*
187 * Both header and payload must be moved the same
188 * amount of bytes to align them properly. This means
189 * we don't use the L2 padding but just move the entire
190 * frame.
191 */
192 rt2x00queue_align_frame(skb);
193 } else if (!payload_align) {
194 /*
195 * Simple L2 padding, only the header needs to be moved,
196 * the payload is already properly aligned.
197 */
198 skb_push(skb, header_align);
199 memmove(skb->data, skb->data + header_align, frame_length);
200 skbdesc->flags |= SKBDESC_L2_PADDED;
173 } else { 201 } else {
174 /* Generic payload alignment to 4-byte boundary */ 202 /*
175 skb_push(skb, align); 203 *
176 memmove(skb->data, skb->data + align, frame_length); 204 * Complicated L2 padding, both header and payload need
205 * to be moved. By default we only move to the start
206 * of the buffer, so our header alignment needs to be
207 * increased if there is not enough room for the header
208 * to be moved.
209 */
210 if (payload_align > header_align)
211 header_align += 4;
212
213 skb_push(skb, header_align);
214 memmove(skb->data, skb->data + header_align, header_length);
215 memmove(skb->data + header_length + l2pad,
216 skb->data + header_length + l2pad + header_align,
217 frame_length - header_length);
218 skbdesc->flags |= SKBDESC_L2_PADDED;
177 } 219 }
178} 220}
179 221
222void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
223{
224 struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
225 unsigned int l2pad = 4 - (header_length & 3);
226
227 if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
228 return;
229
230 memmove(skb->data + l2pad, skb->data, header_length);
231 skb_pull(skb, l2pad);
232}
233
180static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, 234static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
181 struct txentry_desc *txdesc) 235 struct txentry_desc *txdesc)
182{ 236{
@@ -456,18 +510,15 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
456 /* 510 /*
457 * When DMA allocation is required we should guarentee to the 511 * When DMA allocation is required we should guarentee to the
458 * driver that the DMA is aligned to a 4-byte boundary. 512 * driver that the DMA is aligned to a 4-byte boundary.
459 * Aligning the header to this boundary can be done by calling
460 * rt2x00queue_payload_align with the header length of 0.
461 * However some drivers require L2 padding to pad the payload 513 * However some drivers require L2 padding to pad the payload
462 * rather then the header. This could be a requirement for 514 * rather then the header. This could be a requirement for
463 * PCI and USB devices, while header alignment only is valid 515 * PCI and USB devices, while header alignment only is valid
464 * for PCI devices. 516 * for PCI devices.
465 */ 517 */
466 if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) 518 if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
467 rt2x00queue_payload_align(entry->skb, true, 519 rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
468 txdesc.header_length);
469 else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) 520 else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
470 rt2x00queue_payload_align(entry->skb, false, 0); 521 rt2x00queue_align_frame(entry->skb);
471 522
472 /* 523 /*
473 * It could be possible that the queue was corrupted and this 524 * It could be possible that the queue was corrupted and this