Skip to content

Instantly share code, notes, and snippets.

@dafta
Last active September 13, 2024 22:23
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
@rocket0634
Copy link

rocket0634 commented Sep 12, 2024

I'm not sure what I did, but after a combination of messing around with this script and another script I found on the reddit thread, I did finally managed to get this to work. It felt like I was cheating the system because of how many attempts failed but I finally got it to work once.

I opened the deck and applied an update that came out today. And now the script doesn't work again. Using my previous method of running the script twice is no longer working, either. For that matter, before the update the gadget would still persist even after restarting the system, but after the update, restarting the system now results in the gadget being deleted.

I can't help but to feel that Valve put a hard lockdown on sys in the recent update, or something. I thought I'd at least let you know, just in case the latest update did actually end up killing the script.

I believe that this issue has always been on the deck's side. There's no indication that the script was functioning, and when trying to stop it, it'd say the device (the gadget) doesn't exist, suggesting it was never created in the first place. It would be nice to get more hands on troubleshooting with this, but with the latest update, I'm unsure if there's anything that can be done about it now. Unless I'm messing something up, somehow. I did check the folders that were supposed to be created when the script is run, so the only thing I can guess is that it's actually running the gadget that isn't working, and the script has no way of showcasing it working or not.

DRD is on, and I've disabled/enabled it many times. Doing anything with the bios and messing with the USB cable make no difference. At this point even lsmod is only showing one line, instead of the many I showed before. My BIOS version is still 131. It hasn't changed with the update.

@kolanski
Copy link

I'm not sure what I did, but after a combination of messing around with this script and another script I found on the reddit thread, I did finally managed to get this to work. It felt like I was cheating the system because of how many attempts failed but I finally got it to work once.

I opened the deck and applied an update that came out today. And now the script doesn't work again. Using my previous method of running the script twice is no longer working, either. For that matter, before the update the gadget would still persist even after restarting the system, but after the update, restarting the system now results in the gadget being deleted.

I can't help but to feel that Valve put a hard lockdown on sys in the recent update, or something. I thought I'd at least let you know, just in case the latest update did actually end up killing the script.

I believe that this issue has always been on the deck's side. There's no indication that the script was functioning, and when trying to stop it, it'd say the device (the gadget) doesn't exist, suggesting it was never created in the first place. It would be nice to get more hands on troubleshooting with this, but with the latest update, I'm unsure if there's anything that can be done about it now. Unless I'm messing something up, somehow. I did check the folders that were supposed to be created when the script is run, so the only thing I can guess is that it's actually running the gadget that isn't working, and the script has no way of showcasing it working or not.

DRD is on, and I've disabled/enabled it many times. Doing anything with the bios and messing with the USB cable make no difference. At this point even lsmod is only showing one line, instead of the many I showed before. My BIOS version is still 131. It hasn't changed with the update.

I think we need to freeze steam os version it worked.

@dafta
Copy link
Author

dafta commented Sep 13, 2024

I think we need to freeze steam os version it worked.

What do you mean? How would we freeze the steam os version?

I can't help but to feel that Valve put a hard lockdown on sys in the recent update, or something. I thought I'd at least let you know, just in case the latest update did actually end up killing the script.

It's very likely that an update did end up killing the script, but it's not Valve putting a hard lockdown on anything. This happens every now and again because they aren't currently focused on USB DRD and the drivers sometimes stop working until they fix it. It's just a matter of time until it starts working again. It might even work on the beta right now, or stable if you're on beta. It's also possible that the script needs updating.

There's no indication that the script was functioning

I never added any, this script was mostly a proof of concept.

with the latest update, I'm unsure if there's anything that can be done about it now.

Like I said, it's only a matter of time until it works again, or the script might need updating. I will, however, not be updating this script, it's provided as-is and is and always was just a proof of concept. I'm working on instead adding this feature to my decky plugin, DeckMTP, with the next version, and slowly adding more USB gadgets and features with time.

@rocket0634
Copy link

Ah, I thought the plugin was cancelled since I first saw it mentioned years ago. Is it something you're actively working on, or are you waiting on something else before you can work on it?

The main thing I'd like is to remove the latency in Steam Link between the deck and my PC, since my router is on the other side of the house from where my computer is. And throughout what I've searched, it seemed like this script was the only thing I could find that could do it. Would the plugin be able to do this? And would it be anything I could use within the next year or two?

@dafta
Copy link
Author

dafta commented Sep 13, 2024

No, the plugin was never canceled, some things had to be rewritten first to allow this to happen. I'm still working on it, however this is unpaid work that I'm working on in my free time whenever I'm able to and I'm not burnt out from actual work.

Would the plugin be able to do this?

Both the plugin, and this script if you manage to get it to run, should be able to do this. I've seen people use this script for this exact reason.

And would it be anything I could use within the next year or two?

It's the very next thing on my list of priorities. A couple of months will do it most likely.

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