When AX88xxx hardware packs several incoming frames, it puts second and subsequent frames with 2-byte alignment. This may cause situations when IP layer gets IP packet not aligned at 32-bit word boundary, which in turn may lead to kernel crashes on some hardware, and serious slowdown on other hardware.
The attached patch fixes this by detecting incorrectly aligned frames, and moving those in memory. It does so only architectures other than x86, because alignment issue does not exist on x86, so moving data is just unnecessary overhead there. Signed-off-by: Nikita Youshchenko <[EMAIL PROTECTED]>
--- drivers/usb/net/asix.c~ 2006-10-15 16:20:26.000000000 +0400 +++ drivers/usb/net/asix.c 2006-11-24 11:45:00.133930152 +0300 @@ -690,6 +690,21 @@ return ret; } + +/* AX88xxx hardware sometimes packs several frames into single urb, + * and second and subsequent frames are 2-byte-aligned. + * + * On RISC processors, frames must be aligned at (4n+2) adresses, to avoid + * unaligned accesses to IP header fields, so data move may be required. + * + * On PC processors, data move looks like unnecessary overhead. + */ +#if defined(CONFIG_X86_32) || defined(CONFIG_X86_64) +#undef FIX_FRAME_ALIGNMENT +#else +#define FIX_FRAME_ALIGNMENT +#endif + static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { u8 *head; @@ -697,6 +712,7 @@ char *packet; struct sk_buff *ax_skb; u16 size; + int offset; head = (u8 *) skb->data; memcpy(&header, head, sizeof(header)); @@ -713,8 +729,20 @@ /* get the packet length */ size = (u16) (header & 0x0000ffff); - if ((skb->len) - ((size + 1) & 0xfffe) == 0) + if ((skb->len) - ((size + 1) & 0xfffe) == 0) { +#ifdef FIX_FRAME_ALIGNMENT + offset = ((unsigned long)packet + 2) & 3; +#else + offset = 0; +#endif + if (offset) { + skb->data -= offset; + skb->tail -= offset; + memmove(packet - offset, packet, size); + } + return 2; + } if (size > ETH_FRAME_LEN) { devdbg(dev,"invalid rx length %d", size); return 0; @@ -722,8 +750,17 @@ ax_skb = skb_clone(skb, GFP_ATOMIC); if (ax_skb) { ax_skb->len = size; - ax_skb->data = packet; - ax_skb->tail = packet + size; + +#ifdef FIX_FRAME_ALIGNMENT + offset = ((unsigned long)packet + 2) & 3; +#else + offset = 0; +#endif + ax_skb->data = packet - offset; + ax_skb->tail = packet - offset + size; + if (offset) + memmove(packet - offset, packet, size); + usbnet_skb_return(dev, ax_skb); } else { return 0;
pgpK0fKCP16Jv.pgp
Description: PGP signature
------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel