Pi4 USB-C Gadget

Pi4 Gadget

I’ve previously blogged about using Pi Zero (and Zero W) devices as USB Gadgets. This allows them to be powered and accessed via one of the micro USB sockets and it shows up as both a CD-Drive and a ethernet device.

A recent update to the Raspberry Pi 4 bootloader not only enables the low power mode for the USB hardware, allows the enabling of Network boot and enables data over the USB-C port. The lower power means it should run (without any hats) with the power supplied from a laptop.

Details of how to check/update the bootloader can be found here.

Given that the Pi4 has a Gigabit Ethernet adapter, WiFi and 4 USB sockets (need to keep the power draw low to be safe) and up to 4Gb RAM to go with it’s 4 x 1.5Ghz core processor it makes for a very attractive plugin compute device.

With this enabled all the same script from the Pi Zero’s should just work but here is the updated version for Raspbian Buster.

  • Add dtoverlay=dwc2 to the /boot/config.txt
  • Add modules-load=dwc2 to the end of /boot/cmdline.txt
  • If you have not already enabled ssh then create a empty file called ssh in /boot
  • Add libcomposite to /etc/modules
  • Add denyinterfaces usb0 to /etc/dhcpcd.conf
  • Install dnsmasq with sudo apt-get install dnsmasq
  • Create /etc/dnsmasq.d/usb with following content
interface=usb0
dhcp-range=10.55.0.2,10.55.0.6,255.255.255.248,1h
dhcp-option=3
leasefile-ro
  • Create /etc/network/interfaces.d/usb0 with the following content
auto usb0
allow-hotplug usb0
iface usb0 inet static
  address 10.55.0.1
  netmask 255.255.255.248
  • Create /root/usb.sh
#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p pi4
cd pi4
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
echo 0xEF > bDeviceClass
echo 0x02 > bDeviceSubClass
echo 0x01 > bDeviceProtocol
mkdir -p strings/0x409
echo "fedcba9876543211" > strings/0x409/serialnumber
echo "Ben Hardill" > strings/0x409/manufacturer
echo "PI4 USB Device" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower
# Add functions here
# see gadget configurations below
# End functions
mkdir -p functions/ecm.usb0
HOST="00:dc:c8:f7:75:14" # "HostPC"
SELF="00:dd:dc:eb:6d:a1" # "BadUSB"
echo $HOST > functions/ecm.usb0/host_addr
echo $SELF > functions/ecm.usb0/dev_addr
ln -s functions/ecm.usb0 configs/c.1/
udevadm settle -t 5 || :
ls /sys/class/udc > UDC
ifup usb0
service dnsmasq restart
  • Make /root/usb.sh executable with chmod +x /root/usb.sh
  • Add /root/usb.sh to /etc/rc.local before exit 0 (I really should add a systemd startup script here at some point)

With this setup the Pi4 will show up as a ethernet device with an IP address of 10.55.0.1 and will assign the device you plug it into an IP address via DHCP. This means you can just ssh to pi@10.55.0.1 to start using it.

Addendum

Quick note, not all USB-C cables are equal it seems. I’ve been using this one from Amazon and it works fine.

The latest revision (as of late Feb 2020) of the Pi 4 boards should work with any cable.

There is also now a script to create pre-modified Raspbian images here with a description here and a copy of the modified image here.

153 thoughts on “Pi4 USB-C Gadget”

  1. You can usually skip the static ip/dhcp steps by using MDNS, upon connection both devices should get a link local address (in the 169 range) and the pi will be available via raspberrypi.local hostname.

    1. Yeah, but Windows doesn’t come with a mDNS resolver so you have no way of finding out what link local IP address anything has picked.

        1. I’m waiting for mdns on windows for years, somehow it just doesn’t seem to happen. Your link got my hopes up, yet unfortunately it just explains how to disable the dysfunctional mdns rudiment that comes with windows, in order to allow Apple Bonjour to work again :/
          I wish we were finally over DHCP, but this is actually a neat setup. Thank you, Ben!

    2. Brilliant post- I’m looking to use this with an iPad and mdns would be even better I think. I’m not very experienced with linux setup, so not sure precisely what to change from the instructions above to get that effect. Please could you point out the changes I’d need to make that work? Thanks!

        1. Thanks for your reply. What are my options for ssh connections from iPad to pi 3 without WiFi. Is there a way to hardwire in that you are aware of?

          Thanks

          1. As I said in my last comment, there is no way to do this directly with anything other than a Pi 4 or a Pi Zero. You could try a USB-C ethernet adapter e.g. this but you would need an ethernet cable and the setup would all need to be updated to use eth0 not usb0. You would also need a separate battery to power the Pi. For the cost of the adapter and the battery you might as well just buy a new Pi4.

    3. Can you do something similar using the iPad Pro with the raspberry pi 3 . I remember two years ago I was able to ssh into a zero from a MacBook Pro and I am trying to do the same now from an iPad Pro to a pi 3. Thanks!

      1. No, you can not do this with any of the earlier model b raspberry pis, only the zero and the pi 4. The micro USB socket is only connected to power not the USB controller.

  2. That’s pretty cool, Ben. Is there a way to make the Pi be both an Ethernet gadget and a thumbdrive gadget? Like is there a hub gadget that you can attach other gadgets to?

    1. You can build what is known as a composite device that can have multiple capabilities. The only problem is that when you add a USB Mass Storage option it can not be safely mounted on both the Pi and the Host computer at the same time.

      I have built versions that are ethernet/serial port/CD-ROM before. Where the CD-ROM image holds the docs and the .inf files for windows to get the ethernet adapter working.

      1. Hi, I think I’ve followed instructions but it doesn’t work. I’ve checked the systems log file and when it tries to raise network interfaces I get ‘cannot find device”usb0”’
        Any ideas appreciated, thx

        1. That implies you have either that the dwc2 or libcomposite modules didn’t load or there is a typo in the usb.sh. You can check the loaded modules with `lsmod`

          1. That was ok, the modules were loaded. I finally got it working by using modules-load=dwc2,g_ether

          2. g_ether is the wrong thing to do, this loads a old version of the USB gadget code, it means you have either not made /root/usb.sh executable or there is a typo early on in it as it is not being run.

  3. Hey, I’m checking the linked article on updating the Raspberry Pi 4 boot EEPROM and I’m seeing this:

    “Network and USB boot

    Support for these additional bootmodes will be added in the future via optional bootloader updates. The current schedule is to release network boot first, then USB boot.”

    Is this incorrect? Do I need to opt in to a beta version of the bootloader to get these features?

    Thanks

    1. No, those features are not what we are taking about here (but will be great when they arrive).

      You need to make sure that you are on the latest version of the release bootloader as that reduces the power usage of the USB stack which means that powering the Pi4 from a laptop less likely to be a problem.

  4. Great post. Is there a way to get this to work with Kali Linux? I followed the instructions above and it worked with raspbian great….it is not working with the Kail Linux version made for raspberry Pi

  5. Hey,
    thanks a lot for this post!

    I got that working connecting the raspi via USB-C to my MacBook.

    However, there is a mistake in your dnsmasq configuration. The dhcp-range setting takes (start-addr),(end-addr),(subnet-mask),(lease-time) but somehow you have the 10.55.0.0 between and . That makes dnsmasq use 10.55.0.0 as the subnet mask, which is wrong and does not work. The correct subnet mask is 255.255.255.248.

    Just leave that 10.55.0.0 out out that line, and everything is perfect 🙂

    dhcp-range=10.55.0.2,10.55.0.6,255.255.255.248,1h

    Cheers and thanks for this cool idea!

  6. Thank you for the article. When I connect my Pi to the iPad, there is no power led illuminated on the RaspberryPi. Has anyone encountered and solved this?

      1. I can confirm that usb-c 3.1 cables will not work with iPad. I was able to make it work with an Amazon basics usb-c 2.0 cable.

    1. Hi, it’s Rob from Tech Craft. I’m thinking you might be here because of the video I posted on YouTube.

      The most common issue I’ve seen with the Pi not working from the iPad is with the cable. The list that Ben linked to contains all the cables that are known to work with the Pi 4.

      I’ve specifically tested the Anker Powerline with the Pi and iPad.

  7. A couple of points for Raspberry Pi newbies:
    * You have to enable SSH on the Raspberry Pi 4 (Settings)
    * Make sure you do a:
    sudo chmod +x /root/usb.sh

  8. Curious if you’ve tried/gotten this to work with Android? I’ve got your setup working and it does work when plugged into my laptop but can’t seem to get it to function on and Android phone.

  9. I did all the steps 3 times, but when I try to use my apple macbook pro usb c to usb cable to connect my ipad or macbook and the raspberry pi the pi never turns on

  10. Thanks for this – works pretty fine.

    Do you have a solution to share the Internet Connection of the iPad in this configuration?

    1. As I said in a earlier comment I don’t have an iPad so don’t know. I don’t expect this will work but you can do what I do with the Pi Zeros.

      Add the following to /etc/dnsmasq.d/usb

      dhcp-script=/root/route.sh
      leasefile-ro

      And then create a file called /root/route.sh with the following:

      #!/bin/bash
      op="${1:-op}"
      mac="${2:-mac}"
      ip="${3:-ip}"
      host="${4}"

      if [[ $op == "init" ]]; then
      exit 0
      fi

      if [[ $op == "add" ]] || [[ $op == "old" ]]; then
      route add default gw $ip usb0
      fi

      This will set the iPad to be the default route for the Pi. If the iPad is able to do NAT then it will work.

      1. I don’t have an iPad but I do attach my Pi to my laptop (Macbook) and was hoping to get internet access from the PI.

        I added the default route, `route`:
        ““
        default 10.55.0.5 0.0.0.0 UG 0 0 0 usb0
        “`

        But no requests are getting out.

        “`
        bee@bramble:~ $ ping google.com
        ping: google.com: Temporary failure in name resolution

        bee@bramble:~ $ ping -c 1 -W 5 172.217.20.78
        PING 172.217.20.78 (172.217.20.78) 56(84) bytes of data.

        — 172.217.20.78 ping statistics —
        1 packets transmitted, 0 received, 100% packet loss, time 0ms
        “`

        Anything I can do on my end to convince macOS to do the routing? Am I missing anything?

        1. This set of instructions are explicitly setup to make sure the pi is not considered as a router. The intention was for this to just be a way to have a plugin compute device, not a network filtering appliance. But if you want to route via the pi, you need to edit the dnsmasq config file.

          change dhcp-option=3 to dhcp-option=3,10.55.0.1

          DHCP option 3 is the router entry in the DHCP response.

  11. I followed all the steps but the ethernet adapter isn’t showing up on my ipad… i’m still able to ssh into the rpi4 over the wifi though… here’s what the syslog has…

    Nov 30 22:39:41 raspberrypi dnsmasq[564]: dnsmasq: syntax check OK.
    Nov 30 22:39:41 raspberrypi systemd[1]: Started Permit User Sessions.
    Nov 30 22:39:41 raspberrypi systemd[1]: Started Getty on tty1.
    Nov 30 22:39:41 raspberrypi systemd[1]: Reached target Login Prompts.
    Nov 30 22:39:41 raspberrypi dnsmasq[576]: started, version 2.80 cachesize 150
    Nov 30 22:39:41 raspberrypi dnsmasq[576]: compile time options: IPv6 GNU-getopt DBus i18n IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC loop-detect inotify dumpfile
    Nov 30 22:39:41 raspberrypi dnsmasq[576]: warning: interface usb0 does not currently exist
    Nov 30 22:39:41 raspberrypi dnsmasq-dhcp[576]: DHCP, IP range 10.55.0.2 — 10.55.0.6, lease time 1h
    Nov 30 22:39:41 raspberrypi dnsmasq[576]: reading /run/dnsmasq/resolv.conf
    Nov 30 22:39:41 raspberrypi dnsmasq[576]: using nameserver 10.0.0.1#53
    Nov 30 22:39:41 raspberrypi dnsmasq[576]: read /etc/hosts – 5 addresses
    Nov 30 22:39:41 raspberrypi systemd[1]: Started OpenBSD Secure Shell server.
    Nov 30 22:39:41 raspberrypi dnsmasq[577]: Too few arguments.
    Nov 30 22:39:41 raspberrypi systemd[1]: Started dnsmasq – A lightweight DHCP and caching DNS server.

    1. There isn’t really enough here to work out what’s going wrong, but my first guess would be that the `/root/usb.sh` script has not run. Make sure that the script is executable and is actually getting rung.

      1. i guess i missed the update bootloader step, but its working now. this is so sick! thanks for the guide and help!

        1. I got dispman_vncserver working over usbc from iPad to rpi4 now too! so cool! I followed these couple guides…

          to get gcc++ 4.7 installed:
          https://raspberrypi.stackexchange.com/a/101115

          to install/setup vnc:
          https://raspmer.blogspot.com/2015/07/vnc-server-for-raspberry-pi-with.html

          to set dispmanx_vncserver as autostart service on boot:
          https://discourse.osmc.tv/t/howto-install-a-vnc-server-on-the-raspberry-pi/1517

          the only drawbacks are the framerate (prob around 20fps) and no audio unless you use external headphone jack/speakers)

          hope this helps someone… its pretty neat.

          thanks again!

          1. i’m running retropie/emulationstation without a desktop environment. does realvnc work in that case? i read that dispmanx works without desktop environment so thats why i went that route…

  12. hi, great article, thanks. i got it working with my iPad (yes, i came from Rob’s Tech Craft youtube video), but dhcp doesn’t seem to be working, i have to manually set ethernet on iPad to get access and on manual if i set a router, pi has internet via its wifi, but the iPad then drops its own wifi connection.

    also, in usb.sh, am i supposed to modify your listing with my specific mac addresses?

    1. No need to change the MAC addresses, these are for the 2 virtual ethernet devices that the Pi emulating (one for each end of the connection).

      The dnsmasq DHCP deliberately set up to not issue a router to prevent it taking over the default route.

  13. Thank you so much for this write up. I actually have my Raspberry Pi running Arch Linux, and I once got it up and running correctly, but now I am so frustrated because I had to re-install, and I am unable to get the static IP working again.

    The iPad show’s it connected via Ethernet at this point. But it provides it an IP address that is 169.XXX.XXX.XXX

    When I look at my Raspberry Pi, it seems to think it has an address of 10.55.0.1:

    [greg@rpi ~]$ networkctl status usb0
    4: usb0
    Link File: /usr/lib/systemd/network/99-default.link
    Network File: /etc/systemd/network/usb-network.network
    Type: gadget
    State: routable (configured)
    Path: platform-fe980000.usb
    Driver: g_ether
    HW Address: 00:dd:dc:eb:6d:a1
    Address: 10.55.0.1
    fe80::2dd:dcff:feeb:6da1

    Any thoughts about what might be going wrong?

    1. I’ve not tried this on anything but Raspbian, but it sounds like you have not set up dnsmasq properly so it’s not handing out an IP address to the iPad vai DHCP.

      1. Thank you for your thoughts. I am certain I am just a little less than fully understanding how this is supposed to work. I have tried and tried.

        I wondered if this output might give you a clue:
        [greg@rpi ~]$ ip addr
        1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
        valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host
        valid_lft forever preferred_lft forever
        2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
        link/ether dc:a6:32:20:8f:be brd ff:ff:ff:ff:ff:ff
        3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether dc:a6:32:20:8f:bf brd ff:ff:ff:ff:ff:ff
        inet 192.168.1.221/24 brd 192.168.1.255 scope global dynamic noprefixroute wlan0
        valid_lft 86380sec preferred_lft 86380sec
        inet 192.168.1.222/24 brd 192.168.1.255 scope global secondary noprefixroute wlan0
        valid_lft forever preferred_lft forever
        inet6 2607:fcc8:6c44:9c01:a143:eab5:96d:d9ce/64 scope global dynamic mngtmpaddr noprefixroute
        valid_lft 86383sec preferred_lft 14383sec
        inet6 2607:fcc8:6c44:9c01:5b9b:5354:34e4:b910/64 scope global dynamic noprefixroute
        valid_lft 86382sec preferred_lft 14382sec
        inet6 fe80::923f:213d:1627:f2e6/64 scope link noprefixroute
        valid_lft forever preferred_lft forever
        4: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 00:dd:dc:eb:6d:a1 brd ff:ff:ff:ff:ff:ff
        inet 10.55.0.1/29 scope global usb0
        valid_lft forever preferred_lft forever
        inet6 fe80::2dd:dcff:feeb:6da1/64 scope link
        valid_lft forever preferred_lft forever
        [greg@rpi ~]$ sudo dnsmasq –no-daemon –log-queries=extra
        [sudo] password for greg:
        dnsmasq: started, version 2.80 cachesize 150
        dnsmasq: compile time options: IPv6 GNU-getopt DBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC loop-detect inotify dumpfile
        dnsmasq-dhcp: DHCP, IP range 10.55.0.2 — 10.55.0.6, lease time 1h
        dnsmasq-dhcp: DHCP, sockets bound exclusively to interface usb0
        dnsmasq: reading /etc/resolv.conf
        dnsmasq: using nameserver 192.168.1.1#53
        dnsmasq: read /etc/hosts – 1 addresses
        dnsmasq-dhcp: DHCPDISCOVER(usb0) 00:dc:c8:f7:75:14
        dnsmasq-dhcp: DHCPOFFER(usb0) 10.55.0.5 00:dc:c8:f7:75:14
        dnsmasq-dhcp: DHCPREQUEST(usb0) 10.55.0.5 00:dc:c8:f7:75:14
        dnsmasq-dhcp: DHCPACK(usb0) 10.55.0.5 00:dc:c8:f7:75:14 Gregs-iPad

        dnsmasq is offering 10.55.0.5 and when I look at the iPad it is using 10.55.0.1 as the dns server?

        Thanks again. Understand if you can’t support us all obviously, but I thought I would ask.

  14. Hello. I was able to find the first two files, but starting with ‘etc/modules’ I can’t find the rest. Any help with this?

    1. I’m going to guess that you are trying to edit the files on the SD from a OSx or Windows machine. This will only be able to mount the `/boot` partition on the sdcard and not the `rootfs` partition that has the rest of the files on. The best way to edit/add the files is from the Pi running (and it will need to be running to install dnsmasq), that way all the files will be where I’ve listed them

        1. Yes or connecting it to your WiFi and using ssh to connect to it remotely first. There should be plenty of guides online about adding WiFi details to `/boot/wpa_supplicant` and adding an empty `/boot/ssh` to enable ssh on boot.

          1. Thanks for the quick response. Hopefully I can manage to do it with a hotspot or public WiFi as those are the only two means I have for internet connection.

  15. i did everything but still doesnt show and i cant ssh
    iam using a windows 10 it does make sound like something is connected but doesnt show anything

    1. Windows is tricky, it doesn’t attach the standard driver to the USB Ethernet driver. I need to tweak the `/root/usb.sh` script to make it present the right device information.

      1. Do you know what driver should be manually configured in Windows for this to work? I’ve tried several usb c nic drivers, but nothing seams to work.

        1. No, the problem will be that the driver will need to match the device vendor and product id to work.

          There is a different type of Ethernet device type (RNDIS) that there is a Windows driver for but I’m understand that doesn’t work with OSx and you have to set a bunch of other things to get Windows to match it to the driver. Here is link to somebodies else similar script (to my `/root/usb.sh`) that might work. I haven’t tested it as I left my mac in the office for the holidays.

  16. I followed the instructions carefully, but when I try to SSH with that IP I get a “connection refused” message. Any idea why this might be the case?

  17. Thanks for the article: it works great!

    But… when I connect the Pi to my Android tablet (Tab S6) using USB-C, the tablet thinks it now has a wired Ethernet connection and disconnects from the WiFi/LTE.

    Any idea how to avoid this?

    1. No, the DHCP Server settings deliberately doesn’t set a gateway, so the connecting device should realise that there is no onward route to the internet via that route. Newer Android builds don’t seem to be able to handle being dual-homed (connected to 2 networks at once)

      1. Can we not configure the Pi to accept USB tethering from the Android Tablet ?

        My understanding is that the configuration you have here makes the Pi the network router. Can we not do the opposite: have the Pi join the USB network tethered from the Android device?

        Thanks for your help!

        1. In that case you don’t need any of these instructions, back it all out (or start from the fresh image on the sd card) and it should just work. The only problem will be that you don’t know what IP address the Android device will give the pi and I don’t think Avahi/mDNS/bonjour works on Android to use the name.

  18. Hi hardillb,

    I followed your guide, everything is excellent except one thing – I have to manually execute /root/usb.sh everytime pi boots to have pi showed up in my apple.
    sudo /root/usb.sh

    I’ve chmod and added /root/usb.sh in rc.local, I wonder why.
    Noob here any help would be grateful, thanks again~!

  19. Great post! You did a great job of documenting how to do this. Thanks for all the time and effort you put into it, and sharing it with us.

  20. Hi, thank you for this tutorial.
    It looks super cool, but I couldn’t manage to make it work properly. My raspberry is detected by my computer via USB but windows doesn’t find the drivers and I can’t connect to the IP : 10.55.0.1 . I’ve looked carefully every points but I didn’t find what I missed.

    1. Your problem is you are using Windows, which doesn’t recognise the right driver to load for the USB ethernet device unlike every other OS.

      1. Thanks for great guide.

        I’ll tried this with a Chromebook and got the Ethernet connection.

        However on Windows 10 on my surface pro it comes up with CNC ECM. As you have mentioned Windows do not recognise this. I’ve tried different RNDIS drivers also. And of cource Google with out any luck.

        Could I ask if you could pin point more the actuall problem?

        1. The problem is that Windows doesn’t have a built in driver for the EMC Ethernet device type but it does have one for the RNDIS device type. Unfortunately it will only actually load it if a number of configuration options are met. Here is a link to a replacement `usb.sh` that I believe meets those conditions, but it won’t work with my Windows 10 machine

  21. Is there something else I need to install before I do what’s on this page? Or do I just follow the instructions on this page and create an files that do not exist?

    1. Just follow the instructions, or read the very last line of the article, it has a link to script that will modify a standard Raspbian Buster image for you and a link to a pre-modified version.

  22. Great info, but a couple questions:

    1) I have an iPad 12.9 latest, and when I plug the Pi 4 B into it, nothing happens (no power). Is that likely to simply be due to the cable? I’ve tried with the iPad charging cable and a Macbook Pro charging cable (Tech dudes recommended cable arrives tonight).

    2) I’ve read the direction, pretty straightforward. I downloaded the full image from the last line of the article, and when I go through I notice that almost everything is there, although the dnsmasq.d entry is `usb0` instead of `usb`.

    But I also noticed that the /root/usb.sh file is not present. Is that because I still need to add that by hand, or has that file now been removed from the requirement?

      1. Yes it’s 99.5% the cable, the Apple supplied ones think the Pi is an Audio device. You probably have a spin 1 version of the Pi4
      2. The pre-built image has some improvements over the description here. Look at the script that builds the image for details here
  23. Hey,

    I didn’t get the part when you said “Add /root/usb.sh to /etc/rc.local before exit 0”. Could you please clear it up?

    Thanks!

    1. I’m not sure how to be much more explicit. You need to edit /etc/rc.local and insert /boot/usb.sh before the line that says exit 0

      Or you could just take the pre-built image linked to at the end of the post.

    2. Oh, I figured that you just have to put the line “/root/usb.sh” before “exit 0” in the “/etc/rc.local” text file. The way you said it made it look like we have to make a symlink or something. Anyways, thank you for the guide!

  24. Hi Ben!
    Thank you so much for this guide and for a person like me, that have owned a pi (4) for two days, to be able to get this to work on the first try. Thank you!

    I was hoping to be able to ask you a question about how i might use this solution 🙂

    I travel a lot in my work, stay at hotels etc. Our company has a strict policy about open networks at airports, trains and hotels – we’re not allowed to use them.
    I would like to, instead of sharing internet from my phone and drain all my cellular data, to use the pi in between.
    The setup i was thinking is that the pi connect via wifi to an open public network, and i connect to the pi via the USB-C port.

    Is this possible you think? Can i set the pi to forward that wifi-connection via USB-C, so that my iPad and MacBook can use that internet connection? Would i need som kind of software to “mask” my iPad/MB for “a man in the middle” attack? The pi is just providing the internet connecting, it holds nothing of value.

    1. What you are asking is possible but it will require changes to the set up described here. This is specifically set up to stop the connected device using the Pi as a gateway (No gateway is set in the dnsmasq config). It is intended to be a point to point link.

      Secondly just using the pi as a gateway to some open WiFi only provides some protection, it only stops somebody else on that network directly trying to access the connected device, it doesn’t automatically stop things like man in the middle attacks. To do that you would need to include a VPN client and/or a DNS over HTTPS proxy on the Pi and use that to wrap all traffic from the connected device.

      So to reiterate, what you want to do is possible, but it’s a bit too complicated to cover in a comment.

  25. Ben,
    I am an admitted noob. I’ve had my Raspberry Pi 4 for all of three days.

    I followed your instructions explicitly, learned a bit in the process, and it worked like a charm the first time I plugged it in to my iPad Pro.

    Thank you for your efforts!

  26. Great post but hoping you or some other kind soul might be able to help me diagnose an issue I’m having.

    I’ve followed the instructions faithfully with the exception of choosing 10.10.10.x for my IP address range. When connected to my Macbook Pro I can ping and ssh 10.10.10.1 no problem.

    When connected to my iPad Pro however I get nothing. The device does appear in Settings as a network device but doesn’t respond to pings etc. The pi is powering up correctly as I can ssh it via WiFi but not at 10.10.10.1.

    V confused and would welcome any help anyone can offer.

    Alastair

  27. First off, thank you so much for this article.

    Do you know if there is a way to do this in on a pi 4 with Ubuntu rather than raspbian? On Ubuntu there are no /root or /boot dirs so I’m not sure where you would put the scripts. Any advice you may have on this would be appreciated. Thank you again!

    1. I’ve not tried on Ubuntu (might look at the weekend if I get time). But it will definitely have /boot and it doesn’t really matter where you put the usb.sh script as long as you can point to it at startup e.g. /etc/rc.local

      1. Thanks for the reply. I did find this post (https://www.raspberrypi.org/forums/viewtopic.php?t=258463#p1615345) that says someone got it working in 18.04 with a PPA. I tried to recreate it in 20.04 LTS server, in hope that the feature/bug fix from the referenced PPA was included in the newer release, but couldn’t get it to work. Thought I would share the info incase you get time to play with it and don’t want to start from scratch. Cheers!

      2. In case you’re curious – I did some additional testing on this and found that there are a couple of issues:
        1. rc.local does not exist on ubuntu, I think I worked around this by using systemd
        2. newer versions of ubuntu use cloud-init so network interfaces are defined in netplan yaml, not in /etc/network/interfaces.d/. I can’t get the interface to actually show up using the yaml, I have the following question open (https://askubuntu.com/questions/1242648/how-do-i-add-a-usb-c-otg-network-interface-in-20-04-lts) so hopefully someone will answer it as I think this is the last challenge.

  28. Hello.
    Thank you for the brilliant article.
    I was able to connect my RPi 4 and connect to it via ssh
    However, the interface works at USB 2.0 speed. (about 200Mbit/S )
    Is there any way to switch to full speed USB 3.0 with 5GbpS?

    I use a good cable USB Type-C – USB 3.0 Type A.

    I tried change “echo 0x0200 > bcdUSB ” to “0x0300” (from this table https://www.psdevwiki.com/ps4/PS4cam-USB) but it`s not working
    Thanks.

    1. I don’t think the USB-C port is hooked up to a USB 3.0 controller, only a USB 2.0 controller. `lsbusb` shows 2 USB 2.0 controllers and 1 USB 3.0 controller.

  29. First of all, I want to thank you so much for this amazing set of instructions. It enables me to control my pi 4 with the iPad easily, no wifi :).

    But, 64 bit was just released in beta, and I was not able to get the usb-c gadget to work without doing a clean install using your modified image. Once the 64 bit raspberry pi OS is officially released, will you please create a modified image of that with the usb-c gadget? You’re likely a busy man, and I understand if you can’t find the time to do this.

    Thank you for reading this and all you’ve done!

  30. I set my Pi4 USB-C as usb-ethernet. connect to Win PC. Win PC automatically installed driver for usb-eth gadget. and assigned ip address.
    pi4 and win PC could pin and ssh to each other.

    then I connect Pi4 USB-C to Pi3 USB-A.
    at Pi3, lsusb, it sees Linux-USB Ethernet/RNDIS Gadget, but ifconfig
    did not show usb0 ethernet.

    How to make usb0 ethernet work, so Pi3 and Pi4 could communicate via USB connection?

    thanks
    Xian

    1. That should just work. You will have to look at the system logs to work out what is happening.

      But it is worth noting I’m not sure a Pi 3 can deliver enough power via it’s USB ports to drive a Pi 4.

      1. thank you, hardillb. your reply gave me confidence. so I dig into it. now it worked.
        but I don’t know how it worked. first , both side shows usb0 interface. I don’t know why it didn’t when I post this question.
        then I manually ifconfig usb0 ip address. then ping each other.
        ping stuck.
        then I change /etc/dhcpcd.conf on both Pi, set static ip address.
        reboot them.
        now ping each other worked.
        don’t know what’s the difference set ip manually vs by changing /etc/dhcpcd.conf.
        thank you.
        Xian

  31. Hi Ben, thank you, got a question for you: you note that g_ether is bad/old but I find it does work out of the box. I.e. you can just add it to cmdline.txt before ever booting or apt’ing etc and then you can use the gadget and move on. So I’m wondering, what’s the motivation there with using usb.sh vs g_ether? I assume it gives you better speed or maybe wider compatibility? Thanks!

    1. I didn’t say it was bad, I said it was the wrong way to solve the problem that the commenter had hit. But it is the old way of doing this sort of thing and it doesn’t offer the same flexibility that the libcomposite method does.

  32. Hi,

    first, thanks for the great writeup!

    Is it possible to use a USB-A slot on the pi with a USB-A-to-USB-C cable to the iPad?
    With the setup as described here the iPad’s power is drowning rather fast (as mentioned). I recognized, that when the pi has a power plug in the USB-C slot and an iPad is connected from a USB-A (2.0 or 3.0) slot it even recharges as well!
    One could use a USB-C Splitter, as commented earlier, but plugin the iPad into a USB-A slot would be more convenient (as I have that cable already).

    1. No, the USB-A sockets are not capable of working in USB-Gadget mode, because the controller are already running in USB-Host mode to talk to the built in USB hub that breaks them out into multiple ports

  33. The Pi shows up as `CDC ECM` on my Windows 10 machine, but I can not get it to work (no driver).
    Any recommendations for drivers? Or did I do something wrong?

    1. Windows doesn’t support ECM USB Ethernet devices out of the box and any driver would have to match the VendorID/ProductID to work.

      If you use the rpi-gadget-image-creator it has an alternate libcomposite script that will create RNDIS devices that should work with Windows (but not with OSx)

  34. Hi. Interesting guide especially on the ECM and RNDIS on Win10. Thank you!

    Correct me if I am wrong, does the RNDIS work with Win10 but ECM works with OSX and Linux?

    Thanks!

  35. I’m sure I simply missed it, but does this take the whole usb stack of the CPU or are the other usb ports still usable while in gadget mode?
    I’d like to experiment with something like Keyboard forwarding, so this would be cruicial.

  36. Great article thanks. I used this in the past with the Raspberry Pi Zero W. Will try this with the Pi 4.

    I have now a Pi 400 and was wondering if we can use it as an external keyboard. This thread is the closest I could find for this question.

  37. Hi, thank you for the comprehensive guide =)

    could you plz explain a bit what each step is doing?

    For example, you suggest to add this line:

    >Add dtoverlay=dwc2 to the /boot/config.txt

    But I already have this:

    dtoverlay=vc4-fkms-v3d

    Do I have to commend the existing line or add the dwc2 like this:

    dtoverlay=vc4-fkms-v3d-dwc2

    or just keep two lines? =)

    Sorry for stupid questions, newbie =)

    Best regards, Ilia.

  38. Super awesome guide to getting this working on the PI4, it was asked once already, but the answer wasn’t entirely clear. I would like to share my macbook’s ethernet with the RPI when it’s connected by USB.

    I thought it would be as simple as enabling the Internet sharing and selecting the PI4 USB Device in the sharing panel, but this doesn’t work.

    On the PI obviously I would need to add the computer’s ip as the default gateway, which works, but then attempting to ping 1.1.1.1 it doesn’t get routed out (or potentially back properly).

    On the PI: (10.10.10.5 is the macbook, 10.10.10.1 is the RPI)
    ❯ ip r
    default via 10.10.10.5 dev usb0
    default dev usb0 scope link src 169.254.246.156 metric 204
    10.10.10.0/29 dev usb0 proto kernel scope link src 10.10.10.1
    169.254.0.0/16 dev usb0 scope link src 169.254.246.156 metric 204

    Would the easiest way to just configure the RPI’s usb adapter to dhcp it’s address from the macbook?

    1. The script deliberately doesn’t setup any routes as it doesn’t want to convince computer it’s plugged into to try and use it as the default route.

      But if you want to route from the pi via the computer, look at this comment. That script sets the default route on the pi to point to the computer so if you’ve set compute to masquerade (internet sharing) then it should work (assuming the computer still accepts the DHCP address from the pi).

  39. Hello! I would like to send data collected using the Pi 4 to my iPad mini through a custom iOS application. Everything I have seen as listed is for an iPad pro; do other varieties of iPad work as described? My iPad mini does not have a USB-C connection, but a lightning port instead; can I use a USB-C to Lightning adapter cord?

    1. I don’t have any Apple kit, but in theory it the iPad Air with USB-C should behave the same as the iPad Pro. The only thing I can think is that the battery will be smaller on the Air so won’t run as long.

  40. Hi!

    I love this guide so far, but unfortunately, although I think I configured everything as supposed, I’m unable to get it working.

    Checking the logs I’ve found the following info:

    ene 29 17:57:47 raspberrypi systemd[1]: Starting Raise network interfaces…
    ene 29 17:57:48 raspberrypi ifup[444]: Cannot find device “usb0”
    ene 29 17:57:48 raspberrypi ifup[444]: ifup: failed to bring up usb0
    ene 29 17:57:48 raspberrypi systemd[1]: networking.service: Main process exited, code=exited, status=1/FAILURE
    ene 29 17:57:48 raspberrypi systemd[1]: networking.service: Failed with result ‘exit-code’.
    ene 29 17:57:48 raspberrypi systemd[1]: Failed to start Raise network interfaces.

    But then I do see the iface usb0 as DOWN when I list it with the ip link show command.

    Any recommendations on why this could be failing? I installed the last Raspberry OS that you can found in the webpage, and I also tried with this image your script to create pre-modified images with no luck either.

    If you could give me any tips I would really appreciate it!

    Thanks for this tutorial once more!

    Cheers,
    Fernando

    1. Best guess (assuming this is a Pi4) is that you have an early (I think they fixed the latest versions) Pi4 and you need a different USB-C cable. The way to test would be to run `ip link set usb0 up` and see if the link comes up.

      This is definitely the most likely case if you have tried either of the 2 pre-built images linked to as those are known to work.

  41. Hi, can i use this to make my raspberry pi push its wifi connection to the ipads ethernet, so that my ipad connects via the pi to the internet instead through wifi?

    1. As mentioned in some of the other comments, yes it’s possible but these instructions are specifically setup up NOT to do this, they create a single point to point link between the connected device and the Pi, Changes would need to be made to the DNSMasq setup and you would probably also need to setup IP masquerading on the Pi.

  42. Hi,

    is it possible to apply gadget if I connect Raspberry with PC using a USB-CUSB-A cable? My computer is a tower PC (not laptop) and it has only USB-A ports (and I haven’t got any USB-C to USB-A adapter).

    Thanks.

      1. I got my RPi4 to work with your instructions (thank you!!) using a USB-A to USB-C cable. It works great plugged into a Linux Mint 22 laptop.

        I would love to get it to work plugging into a Windows 10 machine … but so far, no go. (But I haven’t done much digging on how to do it yet.)

        Thanks again!!

  43. Is it possible to do the same on CM4? For some reasons does not work, I don’t know what to configure in cmdline and config.txt

    1. No idea, I don’t have any CM4 hardware to test with. It may also depend on which carrier board you have, but again not tried

  44. This blog post was so valuable for me to get started.
    Unfortunately it hardly provided information why those steps and magic numbers are actually working.
    Now that I got confronted with the task of setting up Raspberry Pis again,
    I put everything I learnt in a small number of Ansible roles, uploaded it to https://github.com/bkahlert/pihero
    and called it Pi Hero.

    I also added lots of references, documentation and a ton of screenshots.
    I hope this helps people who read this.

  45. This doesn’t seem to work on the raspberry pi 5, the main problem I find is that running ifconfig will not show usb0 as it did on my pi 4, could you give a hand please?

    1. This looks to be because Raspberry Pi OS Bookworm has moved to using NetworkManager to control network config. I’ll look at the weekend.

          1. The firmware changes are now live, `rpi-update` to install (not fully released for apt install so do so at your own risk). But the rpi-image-creator scripts need updates to properly support Bookworm as it now uses NetworkManager.

  46. I have made this work on a pi5 with Bookworm to allow me to power and connect via Ethernet over usb-c.

    The best way that I can find is to use the g_ether module (as the composite module does not work under windows, which allows the RNDIS windows drivers to work, and this config also works under Linux and on my iPad (no Mac to test on at the moment). This is the “old” way of doing things, but I want it to work with Windows.

    By creating the file /etc/network/interfaces.d/usb0, this stops NetworkManager interfering with the usb interface. (Don’t forget to systemctl enabe this 🙂 )

    The DHCP can then be handled by dnsmasq, as detailed. As there is no dhcpd installed, the config step for that can be omitted.

    It is straightforward – I messed with the composite mode above, and trying to get NetworkManager to manage the interface, but all it seemed to do was be complex and I couldn’t make the configs work …

    Hope this helps

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.