viveris / uMTP-Responder

Lightweight USB Media Transfer Protocol (MTP) responder daemon for GNU/Linux
GNU General Public License v3.0
192 stars 52 forks source link

RNDIS/CDC + MTP #78

Closed cavricks closed 2 years ago

cavricks commented 2 years ago

Hello,

Does anyone have been able to make RNDIS/CDC work along with MTP?

After some particular command sequencing I was able to bind the three functions together, but MTP is never recognized by my windows machine in the other side when RNDIS is activated.

You see, I am not very bright when it comes to the USB stack, but is it because MTP and RNDIS cannot share the interface level or am I missing something?

Let me know if I can be of any help on this, I can post reproduction steps, config files and my scripts if needed.

Cheers, Rick

jfdelnero commented 2 years ago

Yes, i have done this some months ago on another project :

https://sourceforge.net/p/hxcfloppyemu/code/HEAD/tree/HxCFloppyEmulator/Pauline/trunk/Linux_Pauline/targets/Pauline_RevA_de10-nano/config/rootfs_cfg/etc/rcS.d/S96_usbdevice.sh

This configuration was tested against Windows 10 and Linux machines.

#!/bin/sh
#
# References:
#   http://answers.microsoft.com/en-us/windows/forum/windows_10-networking/
#       windows-10-vs-remote-ndis-ethernet-usbgadget-not/cb30520a-753c-4219-b908-ad3d45590447
#

modprobe libcomposite
mount -t configfs none /sys/kernel/config

set -e

g=/sys/kernel/config/usb_gadget/device

# Device name can be retrieved from /sys/class/udc/
device="ffb40000.usb"

usb_ver="0x0200" # USB 2.0
dev_ver="0x0100"
dev_class="0xef"
dev_subclass="0x02"
dev_protocol="0x01"
vid="0x1d50"
pid="0x60c8"
mfg="HxC2001"
prod="Pauline"
serial="0123456789"
attr="0x80" # Bus powered
pwr="500" # mA
cfg1="RNDIS"
cfg2="CDC"
mac="01:23:45:67:89:ab"
# Change the first number for each MAC address - the second digit of 2 indicates
# that these are "locally assigned (b2=1), unicast (b1=0)" addresses. This is
# so that they don't conflict with any existing vendors. Care should be taken
# not to change these two bits.
dev_mac="02$(echo ${mac} | cut -b 3-)"
host_mac="12$(echo ${mac} | cut -b 3-)"
ms_vendor_code="0xcd" # Microsoft
ms_qw_sign="MSFT100" # also Microsoft (if you couldn't tell)
ms_compat_id="RNDIS" # matches Windows RNDIS Drivers
ms_subcompat_id="5162001" # matches Windows RNDIS 6.0 Driver

# Create a new gadget

mkdir -p ${g}
echo "${dev_ver}" > ${g}/bcdDevice
echo "${usb_ver}" > ${g}/bcdUSB
echo "${dev_class}" > ${g}/bDeviceClass
echo "${dev_subclass}" > ${g}/bDeviceSubClass
echo "${dev_protocol}" > ${g}/bDeviceProtocol
echo "${vid}" > ${g}/idVendor
echo "${pid}" > ${g}/idProduct
mkdir ${g}/strings/0x409
echo "${mfg}" > ${g}/strings/0x409/manufacturer
echo "${prod}" > ${g}/strings/0x409/product
echo "${serial}" > ${g}/strings/0x409/serialnumber

# Create 2 configurations. The first will be RNDIS, which is required by
# Windows to be first. The second will be CDC. Linux and Mac are smart
# enough to ignore RNDIS and load the CDC configuration.

# config 1 is for RNDIS

mkdir ${g}/configs/c.1
echo "${attr}" > ${g}/configs/c.1/bmAttributes
echo "${pwr}" > ${g}/configs/c.1/MaxPower
mkdir ${g}/configs/c.1/strings/0x409
echo "${cfg1}" > ${g}/configs/c.1/strings/0x409/configuration

# On Windows 7 and later, the RNDIS 5.1 driver would be used by default,
# but it does not work very well. The RNDIS 6.0 driver works better. In
# order to get this driver to load automatically, we have to use a
# Microsoft-specific extension of USB.

echo "1" > ${g}/os_desc/use
echo "${ms_vendor_code}" > ${g}/os_desc/b_vendor_code
echo "${ms_qw_sign}" > ${g}/os_desc/qw_sign

# Create the RNDIS function, including the Microsoft-specific bits

mkdir ${g}/functions/rndis.usb0
echo "${dev_mac}" > ${g}/functions/rndis.usb0/dev_addr
echo "${host_mac}" > ${g}/functions/rndis.usb0/host_addr
echo "${ms_compat_id}" > ${g}/functions/rndis.usb0/os_desc/interface.rndis/compatible_id
echo "${ms_subcompat_id}" > ${g}/functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id

# config 2 is for CDC
# Note : Windows doesn't support dual configuration composite devices !
# ECM Disabled for the moment...
#mkdir ${g}/configs/c.2
#echo "${attr}" > ${g}/configs/c.2/bmAttributes
#echo "${pwr}" > ${g}/configs/c.2/MaxPower
#mkdir ${g}/configs/c.2/strings/0x409
#echo "${cfg2}" > ${g}/configs/c.2/strings/0x409/configuration

# Create the CDC ECM function

mkdir ${g}/functions/ecm.usb0
echo "${dev_mac}" > ${g}/functions/ecm.usb0/dev_addr
echo "${host_mac}" > ${g}/functions/ecm.usb0/host_addr

# Create the CDC ACM functions (common for both configurations)

#mkdir ${g}/functions/acm.GS0
#mkdir ${g}/functions/acm.GS1

# MTP function

mkdir ${g}/functions/ffs.mtp

# Link everything up and bind the USB device

ln -s ${g}/configs/c.1          ${g}/os_desc

ln -s ${g}/functions/rndis.usb0 ${g}/configs/c.1
ln -s ${g}/functions/ecm.usb0   ${g}/configs/c.1
#ln -s ${g}/functions/acm.GS0    ${g}/configs/c.1
#ln -s ${g}/functions/acm.GS1    ${g}/configs/c.1
ln -s ${g}/functions/ffs.mtp    ${g}/configs/c.1

#ln -s ${g}/functions/ecm.usb0   ${g}/configs/c.2
#ln -s ${g}/functions/acm.GS0    ${g}/configs/c.2
#ln -s ${g}/functions/acm.GS1    ${g}/configs/c.2
#ln -s ${g}/functions/ffs.mtp    ${g}/configs/c.2

mkdir /dev/ffs-mtp
mount -t functionfs mtp /dev/ffs-mtp

# Start the umtprd service
umtprd &

sleep 1

echo "${device}" > ${g}/UDC

ifconfig usb0 192.168.168.1
ifconfig usb1 192.168.169.1

dhcpd
cavricks commented 2 years ago

Hello,

I can confirm you script works also on windows 11.

I'd like to point out some things that might help others:

  1. The following errors were appearing because umtprd was taking more than one second to start and then exiting when the device binding did not occur (echo "${device}" > ${g}/UDC). I increased the time sleep and everything started working.
    • 135: echo: echo: I/O error
    • configfs-gadget ci_hdrc.0: failed to start device: -19
    • bash: echo: write error: No such device
  2. My script although similar was also failing for the following reason:
    • Windows does not accept two configurations for the same gadget (pointed out in @jfdelnero 's script).

In the future I will also try adding serial interfaces to the gadget, so I will come back later if I find any issues adding even more interfaces to that configuration.

Thanks a lot, Rick