Skip to content

Instantly share code, notes, and snippets.

@dafta
Last active July 19, 2024 07:58
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
@MYSK-D25N
Copy link

EDIT: I tried downgrading to BIOS 115, but SteamOS auto-updated to BIOS 116. I then manually flashed BIOS 118, and now DRD works.

Sometime ago the script stopped working for me too. After downgrading BIOS from 120 to 118 today, everything works as intended.

@dafta
Copy link
Author

dafta commented Feb 14, 2024

BIOS 221 should also work.

@ArcaneNibble
Copy link

I'm not using this exact script, but in order to make gadget mode work on BIOS F7A0120 I needed the following commands:

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

@dafta
Copy link
Author

dafta commented Mar 6, 2024

I'm not using this exact script, but in order to make gadget mode work on BIOS F7A0120 I needed the following commands:

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

This is with DRD enabled in the BIOS?

@ArcaneNibble
Copy link

I'm not using this exact script, but in order to make gadget mode work on BIOS F7A0120 I needed the following commands:

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

This is with DRD enabled in the BIOS?

Yes, the BIOS setting still has to be DRD

@dafta
Copy link
Author

dafta commented Mar 7, 2024

I'm not using this exact script, but in order to make gadget mode work on BIOS F7A0120 I needed the following commands:

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

This is with DRD enabled in the BIOS?

Yes, the BIOS setting still has to be DRD

Thanks a ton for figuring this out, this will be a huge help.

@parkerlreed
Copy link

I'm not using this exact script, but in order to make gadget mode work on BIOS F7A0120 I needed the following commands:

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

THANK YOU, This is tremendously helpful.

@MYSK-D25N
Copy link

The abofe gist is for sharing the internet Steam Deck has with some other device that'll be getting its internet access via the Steam Deck.

If you want the opposite, i.e. your Steam Deck using internet from another device, use this gist:

https://gist.github.com/cheater/00279e5b3dea743e14cf7bcd57f6c7fa

Basically it does two things:

  1. disables its own dhcp server
  2. instead of a fixed address, gets its ethernet address from the dhcp server run by the other computer.

Is there any way to get this working while docked? The usb-hub which I use has a USB-C port for data transfers, but upon trying it doesn't seem to work. Maybe I could point it to the port by changing something in the script, I don't really know. Would be cool if possible though.

@dafta
Copy link
Author

dafta commented Apr 25, 2024

@MYSK-D25N Most likely no. To use a dock, the USB port needs to be in host mode, while this script requires the port to be in client mode. There's no way around this, by using this script the USB port goes into client mode and requires the other end to be a PC or device in host mode.

The only way this would work is if your dock exposes a USB device controller (UDC) to the deck. You can check if you have more than one entry in /sys/class/udc, and if you do, you would echo the name of that other UDC to the file in line 167 of the script. But it's a question if the USB C port has Dual-Role Device support, and if the dock has firmware that enables that.

Good luck, and post a reply if you succeed.

@MYSK-D25N
Copy link

@dafta Thanks for the swift reply. It does seem unlikely that my dock is capable of that, there was one entry in UDC folder while nothing is plugged, and then no entries while docked.

Also looked around in dmesg output for clues, the dock shows up there as a "xHCI Host Controller" with the manufacturer as "Linux 6.1.52-valve16-1-neptune-61 xhci-hcd", despite DRD being ON. Didn't find if this can be changed somehow, probably not.

So yeah, doesn't really seem to work, but thanks for clarifying nonetheless.

@EpicestGamer
Copy link

Is there any chance of this being made into a Decky plugin like mentioned here?

@dafta
Copy link
Author

dafta commented Apr 29, 2024

I'm already working on it, but progress is slow when DRD breaks every other update by Valve.

@EpicestGamer
Copy link

Completely fair, glad to hear it. Thank you for all your hard work!

@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.

@FrostEgiant
Copy link

So for the Arch Linux noobs who have stumbled over this script, could I talk someone here into writing up a step-by-step for this? I've done my best to google my way through things-- I'm into hour six of trying-- but I haven't had any luck with it. The script ran, but I honestly don't know what to do next. The deck shows a wired connection (Io) as well as wireless, but either something went wrong halfway through, or something's messed up with the Io connection settings. Ideally I'd like to get it set up so that I can click a shortcut(s?) on the desktop as a toggle, but just really ANY kind of help or guide would be much appreciated. Steam Link over USB is a tantalizing prospect, so I have a hunch I won't be the only one to end up in the weeds on this. Help, pretty please?

@kolanski
Copy link

So for the Arch Linux noobs who have stumbled over this script, could I talk someone here into writing up a step-by-step for this? I've done my best to google my way through things-- I'm into hour six of trying-- but I haven't had any luck with it. The script ran, but I honestly don't know what to do next. The deck shows a wired connection (Io) as well as wireless, but either something went wrong halfway through, or something's messed up with the Io connection settings. Ideally, I'd like to get it set up so that I can click a shortcut(s?) on the desktop as a toggle, but just really ANY kind of help or guide would be much appreciated. Steam Link over USB is a tantalizing prospect, so I have a hunch I won't be the only one to end up in the weeds on this. Help, pretty please?

there are 2 steps you need to additionally:

  1. before running script use
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
  1. after running the script with the correct parameter (it depends on the client OS you want to use) you need to configure either DHCP or static address for host and client.
sudo ip addr add 192.168.100.2/24 dev usb0
sudo ip link set usb0 

next just test via ping or iperf3 -c 192.168.100.1 if you configure 100.x subnet.

@dafta
Copy link
Author

dafta commented Jul 12, 2024

  1. before running script use
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

I added this directly into the script, so this isn't necessary if you have the latest version of the script.

You should also check if you enabled USB DRD in the BIOS, and that you have a recent BIOS version that has working DRD.

@dafta
Copy link
Author

dafta commented Jul 12, 2024

Also, @kolanski I tried the script again to see if it works still, and DHCP was working for me. I'm not sure why it doesn't work for you.

@kolanski
Copy link

Also, @kolanski I tried the script again to see if it works still, and DHCP was working for me. I'm not sure why it doesn't work for you.

I just have old revision of script)

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