[PATCH] usb gadget: ethernet/rndis updates

Updates to the Ethernet/RNDIS gadget driver (mostly for RNDIS):

  - Fix brown-paper bag goof with RNDIS packet TX ... the wrong length
    field got set, so Windows would ignore data packets it received.

  - More consistent handling of CDC output filters (but not yet hooking
    things up so RNDIS uses the mechanism).

  - Zerocopy RX for RNDIS packets too (saving CPU cycles).

  - Use the pre-allocated interrupt/status request and buffer, rather
    than allocating and freeing one of each every few seconds (which
    could fail).

  - Some more "sparse" tweaks, making both dual-speed and single-speed
    configurations happier.

  - RNDIS speeds are reported in units of 100bps, not bps.

Plus two minor cleanups (whitespace, messaging).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 6c51978..7457268 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/system.h>
+#include <asm/unaligned.h>
 
 
 #undef	RNDIS_PM
@@ -165,7 +166,7 @@
 		
 	/* mandatory */
 	case OID_GEN_LINK_SPEED:
-		DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+//		DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
 		length = 4;
 		if (rndis_per_dev_params [configNr].media_state
 			== NDIS_MEDIA_STATE_DISCONNECTED)
@@ -729,7 +730,7 @@
 		retval = 0;
 
 		/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
-		 * filter packets in hard_start_xmit()
+		 * set the cdc_filter; it's not RNDIS-specific
 		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
 		 *	PROMISCUOUS, DIRECTED,
 		 *	MULTICAST, ALL_MULTICAST, BROADCAST
@@ -1194,10 +1195,10 @@
 		return;
 	header = (void *) skb_push (skb, sizeof *header);
 	memset (header, 0, sizeof *header);
-	header->MessageType = __constant_cpu_to_le32 (1);
+	header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
 	header->MessageLength = cpu_to_le32(skb->len);
 	header->DataOffset = __constant_cpu_to_le32 (36);
-	header->OOBDataOffset = cpu_to_le32(skb->len - 44);
+	header->DataLength = cpu_to_le32(skb->len - sizeof *header);
 }
 
 void rndis_free_response (int configNr, u8 *buf)
@@ -1253,26 +1254,23 @@
 	return r;
 }
 
-int rndis_rm_hdr (u8 *buf, u32 *length)
+int rndis_rm_hdr(struct sk_buff *skb)
 {
-	u32 i, messageLen, dataOffset;
-	__le32 *tmp;
-	
-	tmp = (__le32 *) buf; 
+	/* tmp points to a struct rndis_packet_msg_type */
+	__le32		*tmp = (void *) skb->data;
 
-	if (!buf || !length) return -1;
-	if (le32_to_cpup(tmp++) != 1) return -1;
-	
-	messageLen = le32_to_cpup(tmp++);
-	dataOffset = le32_to_cpup(tmp++) + 8;
+	/* MessageType, MessageLength */
+	if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
+			!= get_unaligned(tmp++))
+		return -EINVAL;
+	tmp++;
 
-	if (messageLen < dataOffset || messageLen > *length) return -1;
-	
-	for (i = dataOffset; i < messageLen; i++)
-		buf [i - dataOffset] = buf [i];
-		
-	*length = messageLen - dataOffset;
-	
+	/* DataOffset, DataLength */
+	if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
+			+ 8 /* offset of DataOffset */))
+		return -EOVERFLOW;
+	skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
+
 	return 0;
 }