Hi,

On 4/10/06, David Brownell <[EMAIL PROTECTED]> wrote:
> On Monday 10 April 2006 4:40 am, Ole André Vadla Ravnås wrote:
>
> > >
> > > > Hmm, well http://www.usb.org/developers/defined_class
> > > > says that there is a "misc" protocol for RNDIS, but it
> > > > doesn't match the one you provided (that's for Bluetooth!)
> > > > and there's no spec I can find ...
> > >
> > > Hmm, really? I've used base class 0xEF, sub-class 0x01 and protocol
> > > 0x01, which is what is specified there (if I understood it correctly).
>
> The table is pretty clear; "RNDIS" is 0xe0/1/3 ... and 0xef/1/1 is
> "active sync", not RNDIS.  Something is Still Not Right.

ActiveSync is the name of the software shipped with these devices
which installs an RNDIS driver.  XP, for example, doesn't support
these devices natively. I suspect that they've made it incompatible
just to force people to use the latest version of their software, or,
that they've actually found some other Microsoftish reason to do so...

> ... but of course the Microsoft pointers there do not seem to lead to
> anything like specification,s or AFAICT even a presentation that tells
> developers how and why they're revising either RNDIs or ActiveSync.  That's
> the sort of thing that IMO the EU should be concerned with in terms of
> Microsoft's excuses-for-specs being inadequate to write interoperable
> network software.

Couldn't agree more. It's really sad... :/

> Seems like what you have is updates to the RNDIS driver that probably
> add up to being vendor-specific bug workarounds ... or else add partial
> support for ActiveSync.  If the former, then please recast this patch
> to match against the vendor and product IDs for those devices, rather than
> matching ActiveSync but not RNDIS ... if the latter, please update the
> patch to at least mention that reverse engineering seems to expose the
> fact that ActiveSync builds atop some undocumented subset of RNDIS.

Well, these changes add support for a whole bunch of devices, as the
ActiveSync software is the same for all these devices, which all use
the same driver installed as part of ActiveSync, so it's definitely
the latter.

> And to the extent that it's really ActiveSync glue, it would be better
> to get rid of the tweaks to the CDC descriptor parsing ...

Yes that's true, but considering that the function already has several
workarounds for broken devices I thought they might as well be in one
place. But it is of course your call. :)

Updated patch attached. Changed "Windows Mobile 5" to
"Microsoft.ActiveSync" in the comments and added a clarification that
this new RNDIS "dialect" is undocumented and that this was exposed
through reverse engineering.

Regards,
Ole André
--- linux-2.6.16.2-orig/drivers/usb/net/cdc_ether.c	2006-04-07 19:56:47.000000000 +0300
+++ linux-2.6.16.2/drivers/usb/net/cdc_ether.c	2006-04-11 01:24:55.000000000 +0300
@@ -72,7 +72,8 @@ int usbnet_generic_cdc_bind(struct usbne
 	/* this assumes that if there's a non-RNDIS vendor variant
 	 * of cdc-acm, it'll fail RNDIS requests cleanly.
 	 */
-	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff ||
+		 intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MISC);
 
 	memset(info, 0, sizeof *info);
 	info->control = intf;
@@ -172,6 +173,59 @@ next_desc:
 		buf += buf [0];
 	}
 
+	/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+	 * so to work around this without changing too much of the overall
+	 * logic we fake those headers here.
+	 */
+	if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MISC) {
+		struct usb_cdc_header_desc *h = NULL;
+		struct usb_cdc_union_desc *u = NULL;
+
+		/* allocate and fill the missing structures */
+		h = kmalloc(sizeof(struct usb_cdc_header_desc), GFP_KERNEL);
+		u = kmalloc(sizeof(struct usb_cdc_union_desc), GFP_KERNEL);
+		if (!h || !u) {
+			if (h)
+				kfree(h);
+			if (u)
+				kfree(u);
+
+			return -ENOMEM;
+		}
+		
+		info->header = h;
+
+		h->bLength = sizeof(struct usb_cdc_header_desc);
+		h->bDescriptorType = USB_DT_CS_INTERFACE;
+		h->bDescriptorSubType = USB_CDC_HEADER_TYPE;
+
+		h->bcdCDC = 0;
+		
+		info->u = u;
+
+		u->bLength = sizeof(struct usb_cdc_union_desc);
+		u->bDescriptorType = USB_DT_CS_INTERFACE;
+		u->bDescriptorSubType = USB_CDC_UNION_TYPE;
+		
+		u->bMasterInterface0 = 0;
+		u->bSlaveInterface0 = 1;
+
+		/* initialize */
+		info->control = usb_ifnum_to_if(dev->udev,
+					info->u->bMasterInterface0);
+		info->data = usb_ifnum_to_if(dev->udev,
+					info->u->bSlaveInterface0);
+		if (!info->control || !info->data) {
+			dev_dbg(&intf->dev,
+				"master #%u/%p slave #%u/%p\n",
+				info->u->bMasterInterface0,
+				info->control,
+				info->u->bSlaveInterface0,
+				info->data);
+			goto bad_desc;
+		}
+	}
+	
 	if (!info->header || !info->u || (!rndis && !info->ether)) {
 		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 			info->header ? "" : "header ",
@@ -229,6 +283,17 @@ void usbnet_cdc_unbind(struct usbnet *de
 	struct cdc_state		*info = (void *) &dev->data;
 	struct usb_driver		*driver = driver_of(intf);
 
+	/* clean up resources allocated by the Microsoft ActiveSync
+	 * RNDIS workaround ...
+	 */
+	if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MISC) {
+		if (info->header)
+			kfree(info->header);
+
+		if (info->u)
+			kfree(info->u);
+	}
+
 	/* disconnect master --> disconnect slave */
 	if (intf == info->control && info->data) {
 		/* ensure immediate exit from usbnet_disconnect */
--- linux-2.6.16.2-orig/drivers/usb/net/rndis_host.c	2006-04-07 19:56:47.000000000 +0300
+++ linux-2.6.16.2/drivers/usb/net/rndis_host.c	2006-04-11 01:16:38.000000000 +0300
@@ -377,6 +377,7 @@ static int rndis_bind(struct usbnet *dev
 		struct rndis_set_c	*set_c;
 	} u;
 	u32			tmp;
+	char			*p;
 
 	/* we can't rely on i/o from stack working, or stack allocation */
 	u.buf = kmalloc(1024, GFP_KERNEL);
@@ -409,11 +410,22 @@ fail:
 	dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
 		1 << le32_to_cpu(u.init_c->packet_alignment));
 
-	/* get designated host ethernet address */
-	memset(u.get, 0, sizeof *u.get);
+	/* Get designated host ethernet address.
+	 *
+	 * Adding a payload exactly the same size as the expected
+	 * response' payload is a requirement added by MSFT as of
+	 * post-RNDIS 1.0.  This is completely undocumented and
+	 * was discovered through reverse engineering the driver
+	 * supplied with ActiveSync 4.1. It seems to expose the
+	 * fact that it is built atop some undocumented subset
+	 * of RNDIS.
+	 */
+	memset(u.get, 0, sizeof *u.get + 48);
 	u.get->msg_type = RNDIS_MSG_QUERY;
-	u.get->msg_len = ccpu2(sizeof *u.get);
+	u.get->msg_len = ccpu2(sizeof *u.get + 48);
 	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+	u.get->len = ccpu2(48);
+	u.get->offset = ccpu2(20);
 
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
@@ -575,10 +587,14 @@ static const struct driver_info	rndis_in
 
 /*-------------------------------------------------------------------------*/
 
+#define WM5_SUB_CLASS 0x01
+#define WM5_PROTOCOL  0x01
+
 static const struct usb_device_id	products [] = {
 {
 	/* RNDIS is MSFT's un-official variant of CDC ACM */
 	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+        USB_INTERFACE_INFO(USB_CLASS_MISC, WM5_SUB_CLASS, WM5_PROTOCOL),
 	.driver_info = (unsigned long) &rndis_info,
 },
 	{ },		// END
--- linux-2.6.16.2-orig/include/linux/usb_ch9.h	2006-04-07 19:56:47.000000000 +0300
+++ linux-2.6.16.2/include/linux/usb_ch9.h	2006-04-10 00:22:01.000000000 +0300
@@ -217,6 +217,7 @@ struct usb_device_descriptor {
 #define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
 #define USB_CLASS_VIDEO			0x0e
 #define USB_CLASS_WIRELESS_CONTROLLER	0xe0
+#define USB_CLASS_MISC			0xef
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 










Reply via email to