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;

Attachment: 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

Reply via email to