Skip to content

toolbox: upload the Wi-Fi configuration with escsitoolbox put - #249

Merged
iTechMedic merged 2 commits into
danifunker:mainfrom
iTechMedic:wifi-config-toolbox-upload
Aug 8, 2026
Merged

toolbox: upload the Wi-Fi configuration with escsitoolbox put#249
iTechMedic merged 2 commits into
danifunker:mainfrom
iTechMedic:wifi-config-toolbox-upload

Conversation

@iTechMedic

@iTechMedic iTechMedic commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Closes #87.

WiFi can currently only be set up by pulling the MicroSD card and editing wpa_supplicant.conf on another machine. This adds the standard SCSI Toolbox send-file commands so it can be done over the cable the drive is already on:

scsitb put <device> wpa_supplicant.conf

WIFI.CFG is also accepted, for hosts limited to 8.3 filenames. Either name replaces 0:/wpa_supplicant.conf verbatim — no new WiFi syntax, and the existing WPA parser reads it at the next boot.

Protocol

Standard opcodes only, no new vendor opcode: 0xD3 names the destination, 0xD4 carries 512-byte blocks at absolute indices, 0xD5 closes.

One thing worth knowing: toolbox.h documents SEND_FILE_END as having no payload, but ToolboxSendFileEnd() in the shipping DOS client builds it as a four-byte data-out. Both lengths are accepted and nothing else is, so the released client works unmodified and a client that follows the document also works. Similarly 0xD4 always moves a full 512 bytes whatever CDB[1:2] says is valid, so the transfer is sized from dCBWDataTransferLength and only the declared bytes are copied — the padding is the client's uninitialised buffer.

Scope

This is deliberately not a general shared-directory upload. Only the two Wi-Fi configuration names are accepted; empty names, names with no terminator inside the parameter list, control bytes, path separators, drive prefixes and dot traversal are all refused with ILLEGAL REQUEST before anything is staged. D0, D2, D7, D8, D9 and DA are unchanged.

Safety

The SCSI path runs at IRQ level where FatFs must not be called, so blocks land in a fixed 8 KiB staging buffer and ConfigService::Run does the disk work — the same split that already exists because its setters are called from interrupts and Save() happens in its loop. SCSITBService is not involved.

Nothing touches the card until D5 has returned GOOD. The install then writes a temporary file, checks the byte count (a full card is FR_OK with a short write, not an error return), syncs, and rotates conf.bakconf, since FAT cannot replace atomically. Any failure — short write, bad sync, failed rename, abandoned transfer, USB reset — leaves the working configuration alone and does not reboot. If an install fails and the rollback rename also fails, the old configuration still exists under .bak; that case is logged by name, and the next attempt will not clear a backup that has no working file beside it.

The staging buffer holds a WiFi password, so it is erased through a volatile pointer on every exit path, and the data-out payload is routed by opcode rather than falling through to ProcessOut()'s MODE SELECT parser — whose debug dump would otherwise print the first 24 bytes of a PSK.

The reboot that applies the new configuration is scheduled only after the commit succeeds, and 3 s later, so the CSW reaches the host first.

Tests

25 new tests in integration-tests/test-suite/test_toolbox.cpp drive the real gadget over the bench: the DOS client's exact 33/512/4 transfers, the documented no-payload END, absolute placement and retries, partial final blocks, every fail-closed sequence, oversized and gapped uploads, rejected names and traversal attempts, short and oversized data phases, short-write / sync-failure / rename-failure faults with their rollbacks, and that no password reaches the log or the volume control. The existing toolbox tests are unchanged.

The FatFs host seam gains f_unlink and f_rename, a rename fault injector, and a drive-root mapping so 0:/... paths resolve into a scratch directory.

Run Result
make -C integration-tests 229 tests, 0 failed
WITH_CHD=1 232 tests, 0 failed
ASan + UBSan 229 tests, 0 failed, no diagnostics

Also built clean as a 64-bit Raspberry Pi 3 package.

Open questions

  • The 8 KiB cap is comfortable for WPA but arbitrary; happy to change it.
  • A gap between block indices is rejected. The DOS client is strictly sequential so this never fires in practice, but it is stricter than the published protocol, which allows arbitrary indices.
  • WIFI.CFG and wpa_supplicant.conf both write wpa_supplicant.conf. If WIFI.CFG was meant to be a distinct simplified format, that would be a separate change.
  • Uploading while a disc is mounted means the host sees an unannounced disconnect at the reboot. Let me know if you would rather it ejected first.

Issue danifunker#87. WiFi could only be set up by pulling the MicroSD card and editing wpa_supplicant.conf elsewhere. This adds the standard SCSI Toolbox send-file commands so `scsitb put <dev> wpa_supplicant.conf` does it over the cable the drive is already on.

0xD3 names the destination, 0xD4 carries 512-byte blocks at absolute indices, and 0xD5 closes. The published protocol gives 0xD5 no payload and the DOS client declares four bytes of one, so those two lengths are accepted and no others. No new opcode and no new WiFi syntax; only WIFI.CFG and wpa_supplicant.conf are accepted, so this is not a general file upload.

The SCSI path runs at IRQ level where FatFs must not be called, so blocks land in an 8 KiB buffer and ConfigService::Run writes and syncs a temporary file before rotating it into place and rebooting. Failed installs attempt to restore the working configuration; if rollback also fails, the original remains available as wpa_supplicant.bak. The buffer holds a password, so it is erased through a volatile pointer on every exit and its bytes never reach the log or the MODE SELECT parser.

25 tests drive the real gadget over the bench: the exact client transfers, fail-closed sequences, bounds and name rejection, and rollback under injected filesystem faults.
@iTechMedic
iTechMedic merged commit 408452d into danifunker:main Aug 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create Mechanism to be able to update wifi settings from PC

1 participant