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