aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorNeil Jones <NeilJay@gmail.com>2010-05-17 20:18:28 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-17 20:18:28 -0400
commit3f78d1f210ff89af77f042ab7f4a8fee39feb1c9 (patch)
treef29742a1a73c27a88c7ac701a7a06ac1c2f7973a /drivers/net/usb
parente7a3af5d8cd782b84e6ca4e4dcc8613be1a809f0 (diff)
drivers/net/usb/asix.c: Fix unaligned accesses
Using this driver can cause unaligned accesses in the IP layer This has been fixed by aligning the skb data correctly using the spare room left over by the 4 byte header inserted between packets by the device. Signed-off-by: Neil Jones <NeilJay@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/asix.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 8e7d2374558b..66c5e89326c1 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -322,8 +322,29 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
322 /* get the packet length */ 322 /* get the packet length */
323 size = (u16) (header & 0x0000ffff); 323 size = (u16) (header & 0x0000ffff);
324 324
325 if ((skb->len) - ((size + 1) & 0xfffe) == 0) 325 if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
326 u8 alignment = (u32)skb->data & 0x3;
327 if (alignment != 0x2) {
328 /*
329 * not 16bit aligned so use the room provided by
330 * the 32 bit header to align the data
331 *
332 * note we want 16bit alignment as MAC header is
333 * 14bytes thus ip header will be aligned on
334 * 32bit boundary so accessing ipheader elements
335 * using a cast to struct ip header wont cause
336 * an unaligned accesses.
337 */
338 u8 realignment = (alignment + 2) & 0x3;
339 memmove(skb->data - realignment,
340 skb->data,
341 size);
342 skb->data -= realignment;
343 skb_set_tail_pointer(skb, size);
344 }
326 return 2; 345 return 2;
346 }
347
327 if (size > ETH_FRAME_LEN) { 348 if (size > ETH_FRAME_LEN) {
328 netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", 349 netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
329 size); 350 size);
@@ -331,7 +352,18 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
331 } 352 }
332 ax_skb = skb_clone(skb, GFP_ATOMIC); 353 ax_skb = skb_clone(skb, GFP_ATOMIC);
333 if (ax_skb) { 354 if (ax_skb) {
355 u8 alignment = (u32)packet & 0x3;
334 ax_skb->len = size; 356 ax_skb->len = size;
357
358 if (alignment != 0x2) {
359 /*
360 * not 16bit aligned use the room provided by
361 * the 32 bit header to align the data
362 */
363 u8 realignment = (alignment + 2) & 0x3;
364 memmove(packet - realignment, packet, size);
365 packet -= realignment;
366 }
335 ax_skb->data = packet; 367 ax_skb->data = packet;
336 skb_set_tail_pointer(ax_skb, size); 368 skb_set_tail_pointer(ax_skb, size);
337 usbnet_skb_return(dev, ax_skb); 369 usbnet_skb_return(dev, ax_skb);