Skip to content

Instantly share code, notes, and snippets.

@dafta
Last active June 26, 2024 18:49
Show Gist options
  • Save dafta/0aadeba3aa8bcbbc8b92a233977571ed to your computer and use it in GitHub Desktop.
Save dafta/0aadeba3aa8bcbbc8b92a233977571ed to your computer and use it in GitHub Desktop.
Steam Deck USB Ethernet
#!/bin/sh
if [ "$UID" -ne 0 ]; then
echo "This script needs to be executed as root"
exit 1
fi
vendor_id="0x3000" # Valve
product_id="0x28DE"
serial_number="$(dmidecode -s system-serial-number)" # The Steam Deck's serial number
manufacturer="Valve" # Manufacturer
product="Steam Deck" # Product
device="0x1004" # Device version
usb_version="0x0200" # USB 2.0
device_class="2" # Communications
cfg1="CDC" # Config 1 description
cfg2="RNDIS" # Config 2 description
power=250 # Max power
dev_mac1="42:61:64:55:53:42"
host_mac1="48:6f:73:74:50:43"
dev_mac2="42:61:64:55:53:44"
host_mac2="48:6f:73:74:50:45"
ms_vendor_code="0xcd" # Microsoft
ms_qw_sign="MSFT100" # Microsoft
ms_compat_id="RNDIS" # Matches Windows RNDIS drivers
ms_subcompat_id="5162001" # Matches Windows RNDIS 6.0 driver
cdc_mode="ecm" # Which CDC gadget to use
start_rndis=true # Whether to start the Microsoft RNDIS gadget
while getopts "ncerR" option ${@:2}; do
case "${option}" in
"n")
cdc_mode=ncm
;;
"c")
cdc_mode=ecm
;;
"e")
cdc_mode=eem
;;
"r")
start_rndis=true
;;
"R")
start_rndis=false
;;
esac
done
case "$1" in
start)
# Create the networkd config file for the USB interface
cat << EOF > /etc/systemd/network/usb0.network
[Match]
Name=usb0
[Network]
Address=192.168.100.1/24
DHCPServer=true
IPMasquerade=ipv4
[DHCPServer]
PoolOffset=100
PoolSize=20
EmitDNS=yes
DNS=8.8.8.8
EOF
cat << EOF > /etc/systemd/network/usb1.network
[Match]
Name=usb1
[Network]
Address=192.168.101.1/24
DHCPServer=true
IPMasquerade=ipv4
[DHCPServer]
PoolOffset=100
PoolSize=20
EmitDNS=yes
DNS=8.8.8.8
EOF
# Start networkd
systemctl start systemd-networkd
# Enable DRD driver
echo -n "0000:04:00.3" > /sys/bus/pci/drivers/xhci_hcd/unbind
echo -n "0000:04:00.3" > /sys/bus/pci/drivers/dwc3-pci/bind
# Load the drivers
modprobe libcomposite
# Create the gadget
mkdir /sys/kernel/config/usb_gadget/g.1
cd /sys/kernel/config/usb_gadget/g.1
# Specify the vendor and product ID
echo "${vendor_id}" > idVendor
echo "${product_id}" > idProduct
# Create the gadget configuration
mkdir configs/c.1
# Create the strings directories
mkdir strings/0x409
mkdir configs/c.1/strings/0x409
# Specify the serial number, manufacturer, and product strings
echo "${serial_number}" > strings/0x409/serialnumber
echo "${manufacturer}" > strings/0x409/manufacturer
echo "${product}" > strings/0x409/product
# Specify the device version, USB specification, and device class
echo "${device}" > bcdDevice
echo "${usb_version}" > bcdUSB
echo "${device_class}" > bDeviceClass
# Set the configuration description and power
echo "${cfg1}" > configs/c.1/strings/0x409/configuration
echo "${power}" > configs/c.1/MaxPower
# Create the gadget function
mkdir functions/${cdc_mode}.0
# Set the MAC addresses of the gadget
echo "${host_mac1}" > functions/${cdc_mode}.0/host_addr
echo "${dev_mac1}" > functions/${cdc_mode}.0/dev_addr
# Start RNDIS if enabled
if [ "${start_rndis}" = true ]; then
# Create the gadget configuration
mkdir configs/c.2
# Create the strings directories
mkdir configs/c.2/strings/0x409
# Specify the configuration description and power
echo "${cfg2}" > configs/c.2/strings/0x409/configuration
echo "${power}" > configs/c.2/MaxPower
# Set some Microsoft specific configuration
echo "1" > os_desc/use
echo "${ms_vendor_code}" > os_desc/b_vendor_code
echo "${ms_qw_sign}" > os_desc/qw_sign
# Create the gadget function
mkdir functions/rndis.0
# Set the MAC addresses of the gadget
echo "${host_mac2}" > functions/rndis.0/host_addr
echo "${dev_mac2}" > functions/rndis.0/dev_addr
# Set the RNDIS driver version
echo "${ms_compat_id}" > functions/rndis.0/os_desc/interface.rndis/compatible_id
echo "${ms_subcompat_id}" > functions/rndis.0/os_desc/interface.rndis/sub_compatible_id
fi
# Associate the CDC function with its configuration
ln -s functions/${cdc_mode}.0 configs/c.1/
# Associate the RNDIS function with its configuration
if [ "${start_rndis}" = true ]; then
ln -s functions/rndis.0 configs/c.2
ln -s configs/c.2 os_desc
fi
# Enable the gadget
ls /sys/class/udc > UDC
;;
stop)
# Disable the gadget
cd /sys/kernel/config/usb_gadget/g.1
echo "" > UDC
# Remove functions from the configuration
rm configs/c.1/ncm.0 2> /dev/null
rm configs/c.1/ecm.0 2> /dev/null
rm configs/c.1/eem.0 2> /dev/null
rm configs/c.2/rndis.0 2> /dev/null
# Remove the strings directories in configurations
rmdir configs/c.1/strings/0x409
rmdir configs/c.2/strings/0x409 2> /dev/null
# Remove the configurations
rmdir configs/c.1
rm os_desc/c.2 2> /dev/null
rmdir configs/c.2 2> /dev/null
# Remove the functions
rmdir functions/ncm.0 2> /dev/null
rmdir functions/ecm.0 2> /dev/null
rmdir functions/eem.0 2> /dev/null
rmdir functions/rndis.0 2> /dev/null
# Remove the strings directories in the gadget
rmdir strings/0x409
# Delete the gadget
cd ..
rmdir g.1
# Unload the drivers
cd ../../
modprobe -r usb_f_ncm
modprobe -r usb_f_ecm
modprobe -r usb_f_eem
modprobe -r usb_f_rndis
modprobe -r libcomposite
# Disable DRD driver
echo -n "0000:04:00.3" > /sys/bus/pci/drivers/dwc3-pci/unbind
echo -n "0000:04:00.3" > /sys/bus/pci/drivers/xhci_hcd/bind
# Stop networkd
systemctl stop systemd-networkd 2> /dev/null
# Remove the networkd config files for USB interfaces
rm /etc/systemd/network/usb0.network
rm /etc/systemd/network/usb1.network
;;
*)
echo "Usage:"
echo -e "\t./usb-ether.sh start\tStarts the USB ethernet"
echo -e "\t\t-n\tUse the CDC-NCM USB Ethernet driver (for OSX and iOS)"
echo -e "\t\t-c\tUse the CDC-ECM USB Ethernet driver (default)"
echo -e "\t\t-e\tUse the CDC-EEM USB Ethernet driver"
echo -e "\t\t-r\tEnable the RNDIS USB Ethernet driver for Windows (default)"
echo -e "\t\t-R\tDisable the RNDIS USB Ethernet driver for Windows"
echo -e "\t./usb-ether.sh stop - Stops the USB ethernet"
;;
esac
@indianaliam1
Copy link

so i'm no linux genius, is this an install or a no-install?

@dafta
Copy link
Author

dafta commented May 8, 2024

@indianaliam1 No install, just download and run the script from a terminal.

@kolanski
Copy link

seems didnt work with last update

@heathbarpunch
Copy link

heathbarpunch commented Jun 15, 2024

@kolanski

This from above fixed it for me on the current version:

echo -n "0000:04:00.3" > /sys/bus/pci/drivers/xhci_hcd/unbind
echo -n "0000:04:00.3" > /sys/bus/pci/drivers/dwc3-pci/bind

I had thought I had done this back in May but if I just do sudo then these commands it didn't work. I needed to use "sudo -i" to go into the root user account outright, issue these commands, and then issue the command "exit" to leave and go back to my normal user account.

if you issue the command "sudo lspci -v" from your usual user account you'll be able to see what driver is being used for your different devices, going down to 04.00.3 you'll be able to see if it says xhci or dwc3 as the active driver. For DRD to be the one you are using it needs to show dwc3 as the active driver instead of the xhci.

Ensuring that DRD is selected in the UEFI doesn't seem to be enough to get it to actually use DRD instead of XHCI in the current version.

Edit: Yep, I just disabled, booted, checked, re-enabled, booted, checked and all enabling DRD seems to do in latest builds is allow dwc3 to be an option, but not actually make it the active option, and the script can't make it the active driver either.

@dafta
Copy link
Author

dafta commented Jun 15, 2024

but if I just do sudo then these commands it didn't work. I needed to use "sudo -i" to go into the root user account outright, issue these commands, and then issue the command "exit" to leave and go back to my normal user account.

This is because of how bash works. When you do the above commands with sudo, it's the echo command that's run as root, but the redirect to file is done as the normal bash user and therefore doesn't have permission to write to that file. You can avoid this by replacing the file redirect with the tee command, like this:

echo -n "0000:04:00.3" | sudo tee /sys/bus/pci/drivers/xhci_hcd/unbind
echo -n "0000:04:00.3" | sudo tee /sys/bus/pci/drivers/dwc3-pci/bind

Notice that only tee has sudo in front of it, and not echo.

and the script can't make it the active driver either.

Not sure what you mean by this. In it's current state, yeah it doesn't, but if you add the two commands to the start and end respectively (the original version, you don't need the tee command here because the whole script is run as root), then the script would handle making the correct driver active.

@kolanski
Copy link

@dafta wow, your approach works, all i need its dhcp server in steamdeck, thank you!

@kolanski
Copy link

image
It depends on the cable, speed is better than USB 2.0

@dafta
Copy link
Author

dafta commented Jun 18, 2024

@dafta wow, your approach works, all i need its dhcp server in steamdeck, thank you!

Does the DHCP server not work for you? It should be included in systemd-networkd, and the configuration that's included in this script is supposed to enable the DHCP server on that network, lines 60 and 76.

@kolanski
Copy link

@dafta wow, your approach works, all i need its dhcp server in steamdeck, thank you!

Does the DHCP server not work for you? It should be included in systemd-networkd, and the configuration that's included in this script is supposed to enable the DHCP server on that network, lines 60 and 76.

I have no idea what happens with him, so I just use static address, also I executed this in terminal on steamdeck sudo ip addr add 192.168.100.2/24 dev usb0 for static ip
sudo ip link set usb0 up

@dafta
Copy link
Author

dafta commented Jun 18, 2024

Okay, that's interesting. I'll try and see if it works for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment