RNDIS is deprecated and not safe, we should move to ncm. https://docs.kernel.org/usb/gadget_configfs.html#creating-the-functions
https://www.phoronix.com/news/RNDIS-Disable-Linux-2026-Patch
tested this script, works without drivers on windows & ubuntu, only cleanup needs to be fixed:
#!/bin/dash
# USB Gadget for LEGO MINDSTORMS EV3 hardware
#
# Copyright (C) 2015,2017 David Lechner <david@lechnology.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
set -ex
# command line parameters
command="$1" # "up" or "down"
udc_device="$2" # a udc device name, such as "musb-hdrc.1.auto"
g="/sys/kernel/config/usb_gadget/ev3dev"
ev3_usb_up() {
usb_ver="0x0200" # USB 2.0
dev_class="2" # Communications - LEGO firmware is 0
vid="0x0694" # LEGO Group
pid="0x0009" # EV3
device="0x3002" # this should be incremented any time there are breaking changes
# to this script so that the host OS sees it as a new device and
# re-enumerates everything rather than relying on cached values
mfg="LEGO Group" # matches LEGO firmware
prod="EV3+ev3dev" # LEGO firmware is just "EV3"
# Read bluetooth mac address from eeprom - this is what LEGO firmware uses for serial
# FIXME: hard-coding the sysfs path could be fragile
serial="10" # original does not work anymore for newer kernels, needs 'random' value
attr="0xC0" # Self powered
pwr="1" # 2mA
cfg1="NCM"
cfg2="NCM"
# add colons for MAC address format
mac="$(echo ${serial} | sed 's/\(\w\w\)/:\1/g' | cut -b 2-)"
# 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_mac1="02$(echo ${mac} | cut -b 3-)"
host_mac1="12$(echo ${mac} | cut -b 3-)"
dev_mac2="22$(echo ${mac} | cut -b 3-)"
host_mac2="32$(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
if [ -d ${g} ]; then
if [ "$(cat ${g}/UDC)" != "" ]; then
echo "Gadget is already up."
exit 1
fi
echo "Cleaning up old directory..."
ev3_usb_down
fi
echo "Setting up gadget..."
# Create a new gadget
mkdir ${g}
echo "${usb_ver}" > ${g}/bcdUSB
echo "${dev_class}" > ${g}/bDeviceClass
echo "${vid}" > ${g}/idVendor
echo "${pid}" > ${g}/idProduct
echo "${device}" > ${g}/bcdDevice
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 CDC. The second will be RNDIS.
# Thanks to os_desc, Windows should use the second configuration.
# config 1 is for CDC
# 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
# Create the CDC function
# mkdir ${g}/functions/ecm.usb0
# echo "${dev_mac1}" > ${g}/functions/ecm.usb0/dev_addr
# echo "${host_mac1}" > ${g}/functions/ecm.usb0/host_addr
# config 2 is for NCM
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
# 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 0xbc > ${g}/os_desc/b_vendor_code
echo MSFT100 > ${g}/os_desc/qw_sign
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/ncm.usb0
echo "${dev_mac2}" > ${g}/functions/ncm.usb0/dev_addr
echo "${host_mac2}" > ${g}/functions/ncm.usb0/host_addr
echo WINNCM > ${g}/functions/ncm.usb0/os_desc/interface.ncm/compatible_id
# 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
# Link everything up and bind the USB device
# ln -s ${g}/functions/ecm.usb0 ${g}/configs/c.1
ln -s ${g}/functions/ncm.usb0 ${g}/configs/c.2
ln -s ${g}/configs/c.2 ${g}/os_desc
echo "${udc_device}" > ${g}/UDC
echo "Done."
}
ev3_usb_down() {
if [ ! -d ${g} ]; then
echo "Gadget is already down."
exit 1
fi
echo "Taking down gadget..."
# Have to unlink and remove directories in reverse order.
# Checks allow to finish takedown after error.
if [ "$(cat ${g}/UDC)" != "" ]; then
echo "" > ${g}/UDC
fi
rm -f ${g}/os_desc/c.2
rm -f ${g}/configs/c.2/rndis.usb0
rm -rf ${g}/configs/
rm -f ${g}/configs/c.1/ecm.usb0
[ -d ${g}/functions/ecm.usb0 ] && rmdir ${g}/functions/ecm.usb0
[ -d ${g}/functions/rndis.usb0 ] && rmdir ${g}/functions/rndis.usb0
[ -d ${g}/configs/c.2/strings/0x409 ] && rmdir ${g}/configs/c.2/strings/0x409
[ -d ${g}/configs/c.2 ] && rmdir ${g}/configs/c.2
[ -d ${g}/configs/c.1/strings/0x409 ] && rmdir ${g}/configs/c.1/strings/0x409
[ -d ${g}/configs/c.1 ] && rmdir ${g}/configs/c.1
[ -d ${g}/strings/0x409 ] && rmdir ${g}/strings/0x409
rm -rf ${g}
echo "Done."
}
case ${command} in
up)
ev3_usb_up
;;
down)
ev3_usb_down
;;
*)
echo "Usage: ev3-usb.sh up|down <udc_device>"
exit 1
;;
esac
RNDIS is deprecated and not safe, we should move to ncm. https://docs.kernel.org/usb/gadget_configfs.html#creating-the-functions
https://www.phoronix.com/news/RNDIS-Disable-Linux-2026-Patch
tested this script, works without drivers on windows & ubuntu, only cleanup needs to be fixed: