-
-
Save dafta/0aadeba3aa8bcbbc8b92a233977571ed to your computer and use it in GitHub Desktop.
#!/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 | |
# 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 | |
# 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 |
would make sense. but it would be nice if you could make sure to let people know something like the following: "This option is what you use when you want to connect your Steam Deck to another computer that has internet, in order to access that computer's internet. That computer will have to run a DHCP server and it will have to share its internet with the Steam Deck."
Yeah, definitely. I'd also make the DHCPServer run by default on the Deck, same as RNDIS and ECM already do if you just do ./usb-ether start
you could make the flag something like --client (idk if getopt supports long options now)... maybe -c ...
oh, i guess -c is already being used...
OK, so, i've been trying this thing some more, and it looks like RNDIS will outright not work.
-
it seems like sharing internet to an RNDIS connection in Windows is somehow broken. Not surprised honestly if that were the case. Sometimes it just doesn't run a dhcp server on Windows, and the Deck doesn't get internet. Currently I tried multiple times and now i'm just straight up unable to get internet on the deck like this. However, I also have a dock with ethernet for the deck, and an ethernet dongle, that I can connect to the pc. So if I go from the pc to the sd like pc -> ethernet dongle -> cat 5 -> ethernet dock -> sd, then sharing to that always works.
-
when trying to share internet with multiple devices (I have an xbox plugged into ethernet + the deck which I'd like to connect via usb c) then you have to bridge those devices into a bridge, and share internet to that bridge. In my testing i've never been able to get internet on the Deck like this. Only the xbox got the internet. If I connect the SD via the ethernet dongle route like above, then it gets internet via a bridge too. So in that configuration both the xbox and the deck get internet at once, as well as the PC that is doing the bridging.
So it seems to me like RNDIS is just broken in windows 10. I don't know about windows 11, but I can't imagine it's better.
So for this reason, maybe you could instead figure out a way to use the Ethernet kernel gadget to emulate an ethernet interface?
https://linuxlink.timesys.com/docs/wiki/engineering/HOWTO_Use_USB_Gadget_Ethernet
This way, if I connect the deck to windows, I understand windows would see a new Ethernet connection. But it would think it's a "real deal" Ethernet connection, and not RNDIS. My guess is then windows won't have such issues sharing internet to it.
cc @parkerlreed
Edit: I take it back, the linked to page also works via RNDIS, so following the process outlined in it won't help at all.
This might be some sort of solution. Will have to look into it when I have more time...
Problem is that Windows only supports RNDIS, for reasons only they know. I don't know much about Windows, it might be possible to find a NCM or ECM driver, but by default, they don't support anything else.
This might help, though: https://stackoverflow.com/questions/37630403/composite-usb-cdc-gadget-doesnt-work-with-windows-hosts
Tried to use this for ethernet between Ipad pro to the Steam Deck and it didn't seem to work.. any ideas ?
@tomer-rgo Try using the -n flag. Only the NCM gadget works on iOS.
Nothing happens after executing the script, I found the directory /sys/class/udc
is empty.
Are there any pre-requirements before running the script, or is a reboot required?
And I got the following error message after running ./usb-ether.sh stop
,
./usb-ether.sh: line 173: echo: write error: No such device
@YemingMeng Did you enable USB Dual-Role Device in BIOS?
@YemingMeng Did you enable USB Dual-Role Device in BIOS?
Well, the script works as expected after enabling USB Dual-Role Device, thanks a lot.
This script was working for me, but after updating to SteamOS 3.5 (Main Channel) and then downgrading back to Stable (which upgraded the BIOS), it no longer works for me. I have ensured DRD is still enabled in the BIOS.
BIOS 116 is busted for DRD. Just have to wait for an update or manaully downgrade to 115
Alright. I needed to upgrade the BIOS to fix another issue on my Deck, so I guess I'll just have to wait for an update.
I updated to BIOS 118 and it still doesn't seem to work. Any ideas?
DRD is enabled in the BIOS, but when running sudo ./usb-ether.sh stop
I get:
./usb-ether.sh: line 173: echo: write error: No such device
EDIT: I tried downgrading to BIOS 115, but SteamOS auto-updated to BIOS 116. I then manually flashed BIOS 118, and now DRD works.
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.
BIOS 221 should also work.
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
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?
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/bindThis is with DRD enabled in the BIOS?
Yes, the BIOS setting still has to be DRD
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/bindThis 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.
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.
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:
- disables its own dhcp server
- 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.
@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.
@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.
Is there any chance of this being made into a Decky plugin like mentioned here?
I'm already working on it, but progress is slow when DRD breaks every other update by Valve.
Completely fair, glad to hear it. Thank you for all your hard work!
I can update the script to add a switch to enable or disable the DHCP server. This also requires the other computer to run a DHCP server, or to set up a static IP address manually on both devices.