aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-05-10 07:43:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-05-21 21:47:32 -0400
commit70a96109439cba0af0780ee1dc25ec7ed15f0bae (patch)
tree1e6feb2b77486a90012f117201c13b35ab2020d7 /drivers
parent61448f88078e813bbaaa58eb775d650c85e7d407 (diff)
rt2x00: Preserve descriptor information after memmove()
Due to usage of memmove() in rt2x00usb the descriptor can become corrupted because it is being overwritten by the data part. Overall having the descriptor in front of the frame is a bad idea, we can however use the skb->cb array for this task, since that contains more then enough room to hold the entire descriptor and preserve the information long enough. After this we can also cleanup the alignment code a bit to make it work a bit more flexible to allow for all kinds of odd header lengths. 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/rt2500usb.c23
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c60
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c26
3 files changed, 62 insertions, 47 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 661cf3d7212a..3be4c7ea8dd1 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1129,20 +1129,22 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
1129 __le32 *rxd = 1129 __le32 *rxd =
1130 (__le32 *)(entry->skb->data + 1130 (__le32 *)(entry->skb->data +
1131 (priv_rx->urb->actual_length - entry->queue->desc_size)); 1131 (priv_rx->urb->actual_length - entry->queue->desc_size));
1132 unsigned int offset = entry->queue->desc_size + 2;
1133 u32 word0; 1132 u32 word0;
1134 u32 word1; 1133 u32 word1;
1135 1134
1136 /* 1135 /*
1137 * Copy descriptor to the available headroom inside the skbuffer. 1136 * Copy descriptor to the skb->cb array, this has 2 benefits:
1137 * 1) Each descriptor word is 4 byte aligned.
1138 * 2) Descriptor is safe from moving of frame data in rt2x00usb.
1138 */ 1139 */
1139 skb_push(entry->skb, offset); 1140 skbdesc->desc_len =
1140 memcpy(entry->skb->data, rxd, entry->queue->desc_size); 1141 min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
1141 rxd = (__le32 *)entry->skb->data; 1142 memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
1143 skbdesc->desc = entry->skb->cb;
1144 rxd = (__le32 *)skbdesc->desc;
1142 1145
1143 /* 1146 /*
1144 * The descriptor is now aligned to 4 bytes and thus it is 1147 * It is now safe to read the descriptor on all architectures.
1145 * now safe to read it on all architectures.
1146 */ 1148 */
1147 rt2x00_desc_read(rxd, 0, &word0); 1149 rt2x00_desc_read(rxd, 0, &word0);
1148 rt2x00_desc_read(rxd, 1, &word1); 1150 rt2x00_desc_read(rxd, 1, &word1);
@@ -1173,16 +1175,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
1173 /* 1175 /*
1174 * Adjust the skb memory window to the frame boundaries. 1176 * Adjust the skb memory window to the frame boundaries.
1175 */ 1177 */
1176 skb_pull(entry->skb, offset);
1177 skb_trim(entry->skb, rxdesc->size); 1178 skb_trim(entry->skb, rxdesc->size);
1178
1179 /*
1180 * Set descriptor and data pointer.
1181 */
1182 skbdesc->data = entry->skb->data; 1179 skbdesc->data = entry->skb->data;
1183 skbdesc->data_len = rxdesc->size; 1180 skbdesc->data_len = rxdesc->size;
1184 skbdesc->desc = rxd;
1185 skbdesc->desc_len = entry->queue->desc_size;
1186} 1181}
1187 1182
1188/* 1183/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index caee65e82198..f72b3d07a42d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -246,22 +246,35 @@ static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue)
246{ 246{
247 struct sk_buff *skb; 247 struct sk_buff *skb;
248 unsigned int frame_size; 248 unsigned int frame_size;
249 unsigned int reserved_size;
249 250
250 /* 251 /*
251 * As alignment we use 2 and not NET_IP_ALIGN because we need 252 * The frame size includes descriptor size, because the
252 * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN 253 * hardware directly receive the frame into the skbuffer.
253 * can be 0 on some hardware). We use these 2 bytes for frame
254 * alignment later, we assume that the chance that
255 * header_size % 4 == 2 is bigger then header_size % 2 == 0
256 * and thus optimize alignment by reserving the 2 bytes in
257 * advance.
258 */ 254 */
259 frame_size = queue->data_size + queue->desc_size; 255 frame_size = queue->data_size + queue->desc_size;
260 skb = dev_alloc_skb(queue->desc_size + frame_size + 2); 256
257 /*
258 * For the allocation we should keep a few things in mind:
259 * 1) 4byte alignment of 802.11 payload
260 *
261 * For (1) we need at most 4 bytes to guarentee the correct
262 * alignment. We are going to optimize the fact that the chance
263 * that the 802.11 header_size % 4 == 2 is much bigger then
264 * anything else. However since we need to move the frame up
265 * to 3 bytes to the front, which means we need to preallocate
266 * 6 bytes.
267 */
268 reserved_size = 6;
269
270 /*
271 * Allocate skbuffer.
272 */
273 skb = dev_alloc_skb(frame_size + reserved_size);
261 if (!skb) 274 if (!skb)
262 return NULL; 275 return NULL;
263 276
264 skb_reserve(skb, queue->desc_size + 2); 277 skb_reserve(skb, reserved_size);
265 skb_put(skb, frame_size); 278 skb_put(skb, frame_size);
266 279
267 return skb; 280 return skb;
@@ -274,7 +287,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
274 struct sk_buff *skb; 287 struct sk_buff *skb;
275 struct skb_frame_desc *skbdesc; 288 struct skb_frame_desc *skbdesc;
276 struct rxdone_entry_desc rxdesc; 289 struct rxdone_entry_desc rxdesc;
277 int header_size; 290 unsigned int header_size;
291 unsigned int align;
278 292
279 if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || 293 if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
280 !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) 294 !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
@@ -298,19 +312,29 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
298 memset(&rxdesc, 0, sizeof(rxdesc)); 312 memset(&rxdesc, 0, sizeof(rxdesc));
299 rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); 313 rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
300 314
315 header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
316
301 /* 317 /*
302 * The data behind the ieee80211 header must be 318 * The data behind the ieee80211 header must be
303 * aligned on a 4 byte boundary. 319 * aligned on a 4 byte boundary. We already reserved
320 * 2 bytes for header_size % 4 == 2 optimization.
321 * To determine the number of bytes which the data
322 * should be moved to the left, we must add these
323 * 2 bytes to the header_size.
304 */ 324 */
305 header_size = ieee80211_get_hdrlen_from_skb(entry->skb); 325 align = (header_size + 2) % 4;
306 if (header_size % 4 == 0) { 326
307 skb_push(entry->skb, 2); 327 if (align) {
308 memmove(entry->skb->data, entry->skb->data + 2, 328 skb_push(entry->skb, align);
309 entry->skb->len - 2); 329 /* Move entire frame in 1 command */
310 skbdesc->data = entry->skb->data; 330 memmove(entry->skb->data, entry->skb->data + align,
311 skb_trim(entry->skb,entry->skb->len - 2); 331 rxdesc.size);
312 } 332 }
313 333
334 /* Update data pointers, trim buffer to correct size */
335 skbdesc->data = entry->skb->data;
336 skb_trim(entry->skb, rxdesc.size);
337
314 /* 338 /*
315 * Allocate a new sk buffer to replace the current one. 339 * Allocate a new sk buffer to replace the current one.
316 * If allocation fails, we should drop the current frame 340 * If allocation fails, we should drop the current frame
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 2191d8b94a89..1bcf8c132cdc 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1403,20 +1403,22 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
1403{ 1403{
1404 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 1404 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
1405 __le32 *rxd = (__le32 *)entry->skb->data; 1405 __le32 *rxd = (__le32 *)entry->skb->data;
1406 unsigned int offset = entry->queue->desc_size + 2;
1407 u32 word0; 1406 u32 word0;
1408 u32 word1; 1407 u32 word1;
1409 1408
1410 /* 1409 /*
1411 * Copy descriptor to the available headroom inside the skbuffer. 1410 * Copy descriptor to the skb->cb array, this has 2 benefits:
1411 * 1) Each descriptor word is 4 byte aligned.
1412 * 2) Descriptor is safe from moving of frame data in rt2x00usb.
1412 */ 1413 */
1413 skb_push(entry->skb, offset); 1414 skbdesc->desc_len =
1414 memcpy(entry->skb->data, rxd, entry->queue->desc_size); 1415 min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
1415 rxd = (__le32 *)entry->skb->data; 1416 memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
1417 skbdesc->desc = entry->skb->cb;
1418 rxd = (__le32 *)skbdesc->desc;
1416 1419
1417 /* 1420 /*
1418 * The descriptor is now aligned to 4 bytes and thus it is 1421 * It is now safe to read the descriptor on all architectures.
1419 * now safe to read it on all architectures.
1420 */ 1422 */
1421 rt2x00_desc_read(rxd, 0, &word0); 1423 rt2x00_desc_read(rxd, 0, &word0);
1422 rt2x00_desc_read(rxd, 1, &word1); 1424 rt2x00_desc_read(rxd, 1, &word1);
@@ -1442,18 +1444,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
1442 rxdesc->dev_flags |= RXDONE_MY_BSS; 1444 rxdesc->dev_flags |= RXDONE_MY_BSS;
1443 1445
1444 /* 1446 /*
1445 * Adjust the skb memory window to the frame boundaries. 1447 * Set skb pointers, and update frame information.
1446 */ 1448 */
1447 skb_pull(entry->skb, offset + entry->queue->desc_size); 1449 skb_pull(entry->skb, entry->queue->desc_size);
1448 skb_trim(entry->skb, rxdesc->size); 1450 skb_trim(entry->skb, rxdesc->size);
1449
1450 /*
1451 * Set descriptor and data pointer.
1452 */
1453 skbdesc->data = entry->skb->data; 1451 skbdesc->data = entry->skb->data;
1454 skbdesc->data_len = rxdesc->size; 1452 skbdesc->data_len = rxdesc->size;
1455 skbdesc->desc = rxd;
1456 skbdesc->desc_len = entry->queue->desc_size;
1457} 1453}
1458 1454
1459/* 1455/*