# USB Ethernet and TFTP on the station A USB Ethernet adapter granted to this machine over WebUSB puts it on your local network. With it the machine can fetch files from a TFTP server on that network, and serve files to a board or a host over TFTP. Measured on our bench on 2026-10-06, in Chrome on a Linux host, with a TP-Link USB 10/100 LAN cabled to the bench LAN. Not yet tried: a board's U-Boot fetching its kernel from this machine, an adapter granted from a Mac, and any other adapter. ## 1. What you need - **Developer mode on** for this machine (its Settings). The site then runs the HardwareJS in this image's `/boot`, which handles the adapter. The site's own release refused it when last measured (2026-09-30), with `bad CDC descriptors`. - **A kernel with the USB Ethernet drivers.** Check with `ls /sys/bus/usb/drivers/cdc_ether`; if the directory is not there, this image's kernel does not have them yet. - **An adapter whose driver is built in:** CDC-ECM (`cdc_ether`), CDC-NCM (`cdc_ncm`), DM9601 (`dm9601`) or RTL8153 in ECM mode (`r8153_ecm`). The one we tried is the TP-Link USB 10/100 LAN (`2357:0602`), which binds through `cdc_ether`. Adapters that need `r8152`, `asix` or `ax88179_178a` do not bind (`linux#137`). - **A cable to your network**, and a free static address on it: DHCP does not work in the browser (section 6). ## 2. Let the browser have the adapter (Linux host) The host's own kernel binds the adapter as a network interface, and Chrome then cannot claim it. As root, once: # /etc/udev/rules.d/70-brintos-webusb.rules SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2357", ATTRS{idProduct}=="0602", MODE="0660", GROUP="plugdev", TAG+="uaccess" ACTION=="bind", SUBSYSTEM=="usb", DRIVER=="cdc_ether", ATTRS{idVendor}=="2357", ATTRS{idProduct}=="0602", RUN+="/bin/sh -c 'echo -n %k > /sys/bus/usb/drivers/cdc_ether/unbind'" `udevadm control --reload`, then replug. Use your adapter's IDs from `lsusb`. If `lsusb -t` shows the host bound it with another driver (`r8152`, say), unbind that one instead. The host loses the adapter as its own interface while the rule is installed. On a Mac this has not been tried. ## 3. Attach it and bring it up In the machine's **USB** tab, **Attach USB device**, pick the adapter. Wait about ten seconds, go back to the **Console** tab, then: lsusb # the adapter's ID dmesg | grep -E 'cdc_ether|cdc_ncm|dm9601' | tail -n 3 ip link set eth1 up ip addr add
/24 dev eth1 ip route get # must name eth1 `eth0` is the machine's own virtual network card, which the site provides and relays through the browser. It is not a path to your local network, so leave it alone and put the address on the adapter. If the adapter is not `eth1`, find it by its MAC address: grep -l /sys/class/net/*/address The carrier shows a few seconds after `ip link set … up`: read c < /sys/class/net/eth1/carrier; echo $c # 1 with the cable in ## 4. Fetch a file (TFTP client) tftp -m binary -c get /tmp/ curl --tftp-blksize 8192 -o /tmp/ tftp:/// - `-m binary` matters: `tftp`'s default mode is netascii, which is for text. - `curl` is the faster one, because it asks for larger blocks and the cost through WebUSB is per block (section 7). `tftp` here cannot ask. - Use IP addresses. Nothing configures a name server on the adapter. - **Fetch into `/tmp`.** It is the only memory-backed place for files on a running machine; everything else, `/var/tmp` included, is the machine's own filesystem, which is slow to write (section 7). Files in `/tmp` are gone after a restart and are not part of a snapshot. Check what arrived with `sha256sum /tmp/`. ## 5. Serve files (TFTP server) The server is `in.tftpd-hpa`. It serves `/var/lib/tftpboot`, and reads its options from `/etc/default/tftpd-hpa`. Writing a large file into `/var/lib/tftpboot` is slow: it is the machine's own filesystem, about 17 kB/s, and the 5.8 MB kernel took 337 s. So keep the file in `/tmp` and put a link to it in `/var/lib/tftpboot`: curl --tftp-blksize 8192 -o /tmp/ tftp:/// # or any way into /tmp ln -s /tmp/ /var/lib/tftpboot/ /etc/init.d/tftpd-hpa start grep ':0045 00000000:0000' /proc/net/udp # one line: listening on port 69 A file the image already carries is linked the same way, with no copy at all: ln -s /usr/share/brintos-som/stm32f7/u-boot.bin /var/lib/tftpboot/u-boot.bin Then, from a host or a board on the network, fetch `` from this machine's address, e.g. on a Linux host: curl -o tftp://
/ - Serving through a link was checked across the cable: a host on the LAN fetched U-Boot linked from `/tmp` byte-for-byte, in 6 s. - After a restart the links are still there and `/tmp` is empty: fetch the files into `/tmp` again. - The options are `-l -u root -m /etc/tftpd-hpa.remap /var/lib/tftpboot`. There is no `-s`, because its per-request `chroot()` fails in the browser (`glibc#14`); the remap rule gives a name without a leading `/` the same directory instead. `-u root` is there because this kernel cannot drop privileges (`brintos/linux#19`). - inetutils' `in.tftpd` is on the image too, but it serves only under an inetd, and inetd here handles one request and then stops (`brintos/linux#21`). ## 6. What does not work - **DHCP.** With packet sockets in the kernel, `udhcpc` never returned in the browser, so they are left out and a DHCP client fails at once (`linux#81`). Give the adapter a static address. - **`eth0` to your local network** — see section 3. - **`cat` of a file may print `glibc-wasm32: RESTART-SENTINEL-LEAK val=517 nr=40 …` instead of the file** (`glibc#14`). Read it with `sed -n p `. - **Not tried:** `ping` from the machine, a board's U-Boot fetching from the machine, two adapters at once. - **Copying with `cp`** may hit the same `glibc#14` leak as `cat`; `dd` and `ln -s` do not use the call it leaks from. ## 7. How fast it is The board's 5.8 MB kernel (`rootfs.uImage`), from a TFTP server on the same LAN. "Host" is the Linux PC running Chrome; on its own it fetches the file in about a second. | Transfer | Block size | Time | Throughput | |---|---|---|---| | this machine ← server, `tftp` | 512 B (default) | 123–132 s | 47 kB/s | | this machine ← server, `curl --tftp-blksize` | 1,468 B | 35 s | 164 kB/s | | this machine ← server, `curl --tftp-blksize` | 8,192 B | 11 s | 517 kB/s | | host ← this machine's server | 512 B (default) | 75–84 s | 70 kB/s | | host ← this machine's server | 1,468 B | 29 s | 198 kB/s | | host ← this machine's server | 8,192 B | 9.4 s | 615 kB/s | The first transfer is no slower than the next. The cost is per TFTP block, about 7 to 16 ms each through WebUSB, so larger blocks are what makes it fast. Writing into the machine's own filesystem runs at about 17 kB/s.