rndis_host learns ActiveSync basics

Windows Mobile 5 based devices described as supporting "ActiveSync":

 - Speak RNDIS but lack the CDC and union descriptors.  This patch
   updates the cdc ethernet code to fake ACM descriptors we need.

 - Require RNDIS_MSG_QUERY messages to include a buffer of the size the
   response should generate.  This patch updates the rndis host code to
   pass this will-be-ignored data.

The resulting RNDIS host code has been reported to work with several
WM5 based devices.

(Note that a fancier patch is available at synce.sf.net.)


Some bugfixes, affecting not just ActiveSync:
    (a)	when cleaning up after RNDS init fails, scrub the second interface
	just like cdc_ether does, so disconnect won't oops.
    (b)	handle peripherals that use the pad-to-end-of-packet option; some
	devices can't talk to us if that option doesn't work.
    (c)	when choosing configurations, don't forget about an RNDIS config
	just because the RNDIS driver is dynamically linked.

Cleanup, streamlining, bugfixes, Kconfig, and matching hub driver update.
Also for paranoia's sake, refuse to talk to something that looks like a
real modem instead of RNDIS.

Signed-off-by: Ole Andre Vadla Ravnaas <oleavr@gmail.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>


diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index ebb20ff..b531a4f 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -25,6 +25,20 @@
 	return (n == 1 ? "" : "s");
 }
 
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
 static int choose_configuration(struct usb_device *udev)
 {
 	int i;
@@ -87,14 +101,12 @@
 			continue;
 		}
 
-		/* If the first config's first interface is COMM/2/0xff
-		 * (MSFT RNDIS), rule it out unless Linux has host-side
-		 * RNDIS support. */
-		if (i == 0 && desc
-				&& desc->bInterfaceClass == USB_CLASS_COMM
-				&& desc->bInterfaceSubClass == 2
-				&& desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+		/* When the first config's first interface is one of Microsoft's
+		 * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+		 * this kernel has enabled the necessary host side driver.
+		 */
+		if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
 			continue;
 #else
 			best = c;