Packages¶
The OS is organised as a Buildroot external tree (br2-external). Functionality is split into focused packages under br2-external/package/offlinelab-*/. Each package is self-contained: it installs its own binaries, scripts, and systemd units.
Package overview¶
| Package | Purpose |
|---|---|
offlinelab-base |
Core OS setup: boot partition mount, data partition expansion, fake-hwclock, serial console, /etc/issue |
offlinelab-usb-gadget |
USB composite gadget: ACM serial (ttyGS0) + ECM ethernet (usb0, 10.55.0.1/24) |
offlinelab-wifi |
WiFi via wpa_supplicant, credential provisioning from boot partition |
offlinelab-ssh |
Dropbear SSH, key-only auth, host key generation and key provisioning from boot partition |
offlinelab-zram |
Compressed RAM swap for low-memory operation |
offlinelab-disco |
Service discovery, NSS name resolution, time sync — Phase 2 |
Package structure¶
Each package follows a standard layout:
offlinelab-<name>/
├── Config.in # Buildroot Kconfig options
├── offlinelab-<name>.mk # build rules and install steps
└── src/
├── config/ # scripts and config files
└── systemd/
├── service/ # .service unit files
├── mount/ # .mount unit files
└── network/ # .network files (systemd-networkd)
The .mk file installs everything from src/ into the target rootfs and enables systemd units via symlinks.
Provisioning pattern¶
Several packages implement a common pattern for first-boot configuration:
- A
provision-<x>.serviceunit runs early in the boot sequence. - It checks whether a config file already exists in
/data. If it does, it exits immediately (idempotent). - If not, it copies from the boot partition (
/boot/firmware/config/) to/data.
/boot/firmware/config/wpa_supplicant.conf → /data/config/wifi/wpa_supplicant.conf
/boot/firmware/config/authorized_keys → /data/home/app/.ssh/authorized_keys
The live copy in /data is authoritative. To re-provision, delete the live copy and reboot.
This pattern means the boot partition is never written to at runtime. Config files can be placed there before the first boot using any computer that can mount FAT32.
offlinelab-base¶
Systemd units:
- boot-firmware.mount — mounts /boot/firmware read-only after dev-mmcblk0p1.device appears
- expand-data.service — first-boot data partition resize and format; creates /data directory structure
- fake-hwclock.service — restores last-known time from /data/config/fake-hwclock.data at boot; saves current time on shutdown
Other:
- serial-getty@ttyS0.service — enabled for GPIO UART console (115200 baud)
- getty@tty1.service — enabled for HDMI+keyboard console
- /etc/issue — shows IP addresses for wlan0 and usb0 at the login prompt
offlinelab-usb-gadget¶
Configures the Pi's USB OTG port as a composite gadget providing two functions simultaneously:
- ACM serial (
ttyGS0) —serial-getty@ttyGS0provides a login shell - ECM ethernet (
usb0) —usb0.networkassigns10.55.0.1/24with DHCPServer
The gadget setup script detects whether a USB keyboard or other USB host device is already connected. If so, it stays in USB host mode and skips gadget setup. USB host (keyboard) and gadget mode are mutually exclusive on the Zero 2W OTG port.
offlinelab-wifi¶
Systemd units:
- provision-wifi.service — copies wpa_supplicant.conf from boot partition on first boot
- wifi-setup.service — starts wpa_supplicant after wlan0 appears (BindsTo=sys-subsystem-net-devices-wlan0.device)
Notes:
- wpa_cli is available for runtime WiFi management.
- wlan0.network uses DHCP.
- A kernel module workaround (02w-wifi-fix.conf) addresses a timing issue with the brcmfmac driver on the Zero 2W.
offlinelab-ssh¶
Systemd units:
- provision-ssh.service — generates host keys if absent; copies authorized_keys from boot partition
- dropbear.service — Requires=provision-ssh.service (hard dependency; dropbear won't start without host keys)
Notes:
- Password authentication is disabled. Key-only access only.
- Host keys persist at /data/config/ssh/dropbear/.
- Connect as user app (uid 1000, passwordless sudo).
offlinelab-zram¶
Configures a zram block device as compressed swap:
- Uses LZ4 compression (fast, CPU-efficient)
- Size: half of physical RAM (256MB on Zero 2W)
- Loaded via
modules-load.d(CONFIG_ZRAM=min kernel)
offlinelab-disco¶
Phase 2 — not yet active. Will provide:
- disco-daemon — UDP broadcast discovery and hostname resolution
- libnss_disco.so.2 — glibc NSS module for native hostname resolution
- disco CLI
- Time synchronization from GPS sources
See Disco for the full protocol and design.
Adding a package¶
- Create
br2-external/package/offlinelab-<name>/withConfig.inandofflinelab-<name>.mk. - Add
source "package/offlinelab-<name>/Config.in"tobr2-external/Config.in. - Add the package to the defconfig (
BR2_PACKAGE_OFFLINELAB_<NAME>=y). - Place source files in
src/and install them from the.mkfile.
After editing source files under src/, run make offlinelab-<name>-dirclean before rebuilding — Buildroot won't re-run install steps otherwise.