7
votes

I am developing a RNDIS composite device which includes a RNDIS device, a usbnet device ,a modem device and a self-defined CDC device.

The PC is running Win7 32bit, and I am using the default RNDIS driver. When I answers the Windows enumeration with only RNDIS device, everything works fine. But when I compose all 4 device into the descriptor as composite device, Windows still enumerates correctly and the other 3 devices works fine, but RNDIS device encounters with "cannot start error code 10" issue.

I traced the USB data flow with a USB analyzer, found that Windows RNDIS driver did not send RNDIS initialize messages after “Set Configuration”.

The composite device descriptor is as posted:

         devDesc[0]  = 0x12; //  bLength             - Descriptor length
         devDesc[1]  = 0x01; //  bDescriptorType     - Descriptor  Type
         devDesc[2]  = bcdUSB_LSB; //  bcdUSB (LSB)        - Device Compliant to USB specification ..
         devDesc[3]  = bcdUSB_MSB; //  bcdUSB (MSB)
         devDesc[4]  = 0x00; //  bDeviceClass        - class of the device
         devDesc[5]  = 0x00; //  bDeviceSubClass     - subclass of the device
         devDesc[6]  = 0x00; //  bDeviceProtocol     - protocol of the device
         devDesc[7]  = bEp0MaxPacketSize; //  bMaxPacketSize0     - Max Packet Size for EP zero
         devDesc[8]  = 0x86; //  idVendor (LSB)      - Vendor ID
         devDesc[9]  = 0x12; //  idVendor (MSB)
         devDesc[10] = 0x0E; //  idProduct (LSB)     - Product ID
         devDesc[11] = 0x81; //  idProduct (MSB)
         devDesc[12] = 0x02; //  bcdDevice (LSB)     - The device release number
         devDesc[13] = 0x00; //  bcdDevice (MSB)
         devDesc[14] = 0x01; //  iManufacturer       - Index of string descriptor describing Manufacturer
         devDesc[15] = 0x03; //  iProduct            - Index of string descriptor describing Product
         devDesc[16] = 0x04; //  iSerialNumber       - Index of string descriptor describing Serial number
         devDesc[17] = 0x01; //  bNumConfigurations  - Number of configurations

         //Configuration Descriptor
         configDesc[0]  = 0x09; // bLength               - Descriptor length
         configDesc[1]  = 0x02; // bDescriptorType       - Descriptor Type
         configDesc[2]  = 177;   // wTotalLength (LSB)   - Total Data length for the configuration,
         configDesc[3]  = 0x00; // wTotalLength (MSB)    - includes all descriptors for this configuration
         configDesc[4]  = 0x05; // bNumInterfaces        - Number of interfaces this configuration supports
         configDesc[5]  = 0x01; // bConfigurationValue   - The Value that should be used to select this configuration
         configDesc[6]  = 0x00; // iConfiguration        - Index of string descriptor describing this configuration
         configDesc[7]  = 0xC0; // bmAttributes          - bit6: Self-Powered, bit5: RemoteWakeup
         configDesc[8]  = 0xfa; // MaxPower              - Maximum power consumption for this configuration (mA)


         //Interface Descriptor 0 usbnet
         configDesc[9]  = 0x09; // bLength               - Descriptor length
         configDesc[10] = 0x04; // bDescriptorType       - Descriptor Type
         configDesc[11] = 0x00; // bInterfaceNumber      - Index (Number) of this interfaces
         configDesc[12] = 0x00; // bAlternateSetting     - The value to select alternate setting of this interface
         configDesc[13] = 0x03; // bNumEndpoints         - Number endpoints  used by this interface
         configDesc[14] = 0xff; // bInterfaceClass       - Class of this Interface
         configDesc[15] = 0xff; // bInterfaceSubClass    - Sub class of this Interface
         configDesc[16] = 0x00; // bInterfaceProtocol    - Protocol of this Interface
         configDesc[17] = 0x05; // iInterface            - Index of string descriptor describing this Interface


         // usbnet Endpoint Descriptor
         configDesc[18] = 0x07; // bLength               - Descriptor length
         configDesc[19] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[20] = 0x85; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[21] = 0x03; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[22] = 0x0F; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[23] = 0x00; // wMaxPacketSize (MSB)
         configDesc[24] = bInterval; // bInterval                - Polling Interval (ms)

         configDesc[25] = 0x07; // bLength               - Descriptor length
         configDesc[26] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[27] = 0x81; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[28] = 0x02; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[29] = bBulkMaxPacketSize_LSB; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[30] = bBulkMaxPacketSize_MSB; // wMaxPacketSize (MSB)
         configDesc[31] = 0x00; // bInterval             - Polling Interval (ms)

         configDesc[32] = 0x07; // bLength               - Descriptor length
         configDesc[33] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[34] = 0x02; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[35] = 0x02; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[36] = bBulkMaxPacketSize_LSB; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[37] = bBulkMaxPacketSize_MSB; // wMaxPacketSize (MSB)
         configDesc[38] = 0x00; // bInterval             - Polling Interval (ms)

         //Interface descriptor 1 ICAT
         configDesc[39] = 0x09; // bLength               - Descriptor length
         configDesc[40] = 0x04; // bDescriptorType       - Descriptor Type
         configDesc[41] = 0x01; // bInterfaceNumber      - Index (Number) of this interfaces
         configDesc[42] = 0x00; // bAlternateSetting     - The value to select alternate setting of this interface
         configDesc[43] = 0x02; // bNumEndpoints         - Number endpoints  used by this interface
         configDesc[44] = 0xFF; // bInterfaceClass       - Class of this Interface
         configDesc[45] = 0x00; // bInterfaceSubClass    - Sub class of this Interface
         configDesc[46] = 0x00; // bInterfaceProtocol    - Protocol of this Interface
         configDesc[47] = 0x00; // iInterface            - Index of string descriptor describing this Interface

         //ICAT endpoints
         configDesc[48] = 0x07; // bLength               - Descriptor length
         configDesc[49] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[50] = 0x87; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[51] = 0x02; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[52] = bBulkMaxPacketSize_LSB; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[53] = bBulkMaxPacketSize_MSB; // wMaxPacketSize (MSB)
         configDesc[54] = 0x00; // bInterval             - Polling Interval (ms)

         configDesc[55] = 0x07; // bLength               - Descriptor length
         configDesc[56] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[57] = 0x08; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[58] = 0x02; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[59] = bBulkMaxPacketSize_LSB; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[60] = bBulkMaxPacketSize_MSB; // wMaxPacketSize (MSB)
         configDesc[61] = 0x00; // bInterval             - Polling Interval (ms)

         //Modem class specific descriptors
         configDesc[62]  = 0x09; // bLength              - Descriptor length
         configDesc[63] = 0x04; // bDescriptorType       - Descriptor Type
         configDesc[64] = 0x02; // bInterfaceNumber      - Index (Number) of this interfaces
         configDesc[65] = 0x00; // bAlternateSetting     - The value to select alternate setting of this interface
         configDesc[66] = 0x03; // bNumEndpoints         - Number endpoints  used by this interface
         configDesc[67] = 0x02; // bInterfaceClass       - Class of this Interface
         configDesc[68] = 0x02; // bInterfaceSubClass    - Sub class of this Interface
         configDesc[69] = 0x01; // bInterfaceProtocol    - Protocol of this Interface
         configDesc[70] = 0x00; // iInterface            - Index of string descriptor describing this Interface

         configDesc[71] = 0x05; // descriptor length Comms Class CS_INTERFACE 'Functional Descriptors' Triplet
         configDesc[72] = 0x24; // descriptor type
         configDesc[73] = 0x00; // subtype = header
         configDesc[74] = 0x10; // BCD
         configDesc[75] = 0x01; //

         configDesc[76] = 0x05; // 2. descriptor length - Call Manangement Func Desc
         configDesc[77] = 0x24; // descriptor type
         configDesc[78] = 0x01; // subtype = Call management
         configDesc[79] = 0x00; //bmcapabilities; MS driver usbser.sys seems to ignore this bit and sends AT over the data,interface anyway
         configDesc[80] = 0x01; // Interface number of data class interface

         configDesc[81] = 0x04; // 3.descriptor length  Abstract Control Func Desc
         configDesc[82] = 0x24; // descriptor type
         configDesc[83] = 0x02; // subtype = Abstract CM
         configDesc[84] = 0x00; // bmcapabilities 

         configDesc[85] = 0x05; // Size of descriptor. Number of interfaces plus 3 bytes of header
         configDesc[86] = 0x24; // 0x24 - CS_INTERFACE
         configDesc[87] = 0x06; // 0x06 - See table 25 of document "USB Class definitions for Comms Devices"
         configDesc[88] = 0x00;
         configDesc[89] = 0x01;

         //Endpoint Descriptors MODEM
         configDesc[90] = 0x07; // bLength               - Descriptor length
         configDesc[91] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[92] = 0x86; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[93] = 0x03; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[94] = 0x0F; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[95] = 0x00; // wMaxPacketSize (MSB)
         configDesc[96] = bInterval; // bInterval                - Polling Interval (ms)

         configDesc[97] = 0x07; // bLength               - Descriptor length
         configDesc[98] = 0x05; // bDescriptorType       - Descriptor Type
         configDesc[99] = 0x83; // bEndpointAddress      - Endpoint Address & Direction
         configDesc[100] = 0x02; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[101] = bBulkMaxPacketSize_LSB; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[102] = bBulkMaxPacketSize_MSB; // wMaxPacketSize (MSB)
         configDesc[103] = 0x00; // bInterval                - Polling Interval (ms)

         configDesc[104] = 0x07; // bLength              - Descriptor length
         configDesc[105] = 0x05; // bDescriptorType      - Descriptor Type
         configDesc[106] = 0x04; // bEndpointAddress     - Endpoint Address & Direction
         configDesc[107] = 0x02; // bmAttributes          - BULK,ISO,Interrupt
         configDesc[108] = bBulkMaxPacketSize_LSB; // wMaxPacketSize (LSB)  - Max packet size
         configDesc[109] = bBulkMaxPacketSize_MSB; // wMaxPacketSize (MSB)
         configDesc[110] = 0x00; // bInterval                - Polling Interval (ms)


        //rndis IAD
        configDesc[111] = 0x08; // bLength
        configDesc[112] = 0x0b; // INTERFACE ASSOCIATION DESCRIPTOR bDescriptorType
        configDesc[113] = 0x03; // bFirstInterface
        configDesc[114] = 0x02; // bInterfaceCount
        configDesc[115] = 0x02; // bFunctionClass
        configDesc[116] = 0x02; // bFunctionSubClass
        configDesc[117] = 0xFF; // bFunctionProtocol
        configDesc[118] = 0x03; // Index of string descriptor describing this function

        //rndis comm interface
        configDesc[119] = 0x09; // bLength             - Descriptor length
        configDesc[120] = 0x04; // bDescriptorType     - Descriptor Type
        configDesc[121] = 0x03; //bInterfaceNumber     - for RNDIS
        configDesc[122] = 0x00; // bAlt
        configDesc[123] = 0x01; // bNumEnd
        configDesc[124] = 0x02; //bInterfaceClass
        configDesc[125] = 0x02; // bInterfaceSubclass
        configDesc[126] = 0xFF; // bInterfaceprotocol
        configDesc[127] = 0x00; // iInterface  +++++++++++++++++++++++++++++++++++++need modified


        // Class specified descriptor

        configDesc[128] = 0x05; //
        configDesc[129] = 0x24; // bDescriptorType
        configDesc[130] = 0x00; //bDescriptorSubtype
        configDesc[131] = 0x10; // BCD
        configDesc[132] = 0x01; //

        configDesc[133] = 0x05; //
        configDesc[134] = 0x24; // bDescriptorType
        configDesc[135] = 0x01; // bDescriptorSubtype
        configDesc[136] = 0x00; // bmCapabilities
        configDesc[137] = 0x04; //bDataInterface

        configDesc[138] = 0x04; //
        configDesc[139] = 0x24; // bDescriptorType
        configDesc[140] = 0x02; // bDescriptorSubtype
        configDesc[141] = 0x00; // bmCapabilities

        configDesc[142] = 0x05; //
        configDesc[143] = 0x24; // bDescriptorType
        configDesc[144] = 0x06; // bDescriptorSubtype
        configDesc[145] = 0x03; // bControlInterface
        configDesc[146] = 0x04; // bsubordinateInterface

        //Interrupt In endpoint
        configDesc[147] = 0x07; //
        configDesc[148] = 0x05; //
        configDesc[149] = 0x8C; //bendpointAddress
        configDesc[150] = 0x03; //bmAttributes
        configDesc[151] = 0x08; // wMaxPacketSize
        configDesc[152] = 0x00; //
        configDesc[153] = 0x01; // bInterval

        //rndis data interface
        configDesc[154] = 0x09; // bLength             - Descriptor length
        configDesc[155] = 0x04; // bDescriptorType     - Descriptor Type
        configDesc[156] = 0x04; //bInterfaceNumber     --- for RNDIS
        configDesc[157] = 0x00; // bAlt
        configDesc[158] = 0x02; // NumEndpoints
        configDesc[159] = 0x0a; //bInterfaceClass
        configDesc[160] = 0x00; // bInterfaceSubclass
        configDesc[161] = 0x00; // bInterfaceprotocol
        configDesc[162] = 0x00; // iInterface  +++++++++++++++++++++++++++++++++++++need modified

        //Bulk In endpoint
        configDesc[163] = 0x07; //
        configDesc[164] = 0x05; //
        configDesc[165] = 0x8E; //bendpointAddress
        configDesc[166] = 0x02; //bmAttributes
        configDesc[167] = 0x00; // wMaxPacketSize
        configDesc[168] = 0x02; //
        configDesc[169] = 0x00; // bInterval

        //Bulk Out endpoint
        configDesc[170] = 0x07; //
        configDesc[171] = 0x05; //
        configDesc[172] = 0x0D; //bendpointAddress
        configDesc[173] = 0x02; //bmAttributes
        configDesc[174] = 0x00; // wMaxPacketSize
        configDesc[175] = 0x02; //
        configDesc[176] = 0x00; // bInterva
2

2 Answers

4
votes

Let me answer my own question, I have figured out this issue:

The RNDIS IAD interface must be the first and second of the composite device. Although the problem is solved, it still puzzles me.

Hope this note will help others encountering similar issues.

0
votes

For those of you out there that come across this thread, because you are having similar problems with RNDIS and windows code 10 errors, using the built in configfs libcomposite device, after tons of googling, and going over code on the internet, code in the libcomposite module..... I found that instead of patching the driver I could work around this if I force loaded the usb_f_rndis module directly after libcomposite module, this forces usb_f_rndis to first and second iad slot. The rest of the modules for libcomposite devices will load, as you add the devices in configfs, and Windows will be happy with it.

Also, to force windows to load the right driver, make sure you set up the os_desc stuff. There is a nice guide that goes over that here: http://irq5.io/2016/12/22/raspberry-pi-zero-as-multiple-usb-gadgets/