# Agent guide Use this file as the first-pass context for changes in this package. Read only the module(s) relevant to the task; the public interfaces in `src/*.h` usually provide enough context before opening an implementation. ## Project in one paragraph openUF is a single-process C daemon for OpenWrt. It makes an OpenWrt access point look like a UniFi AP: `main.c` periodically sends L2 discovery, LLDP, and encrypted HTTP inform packets. Controller responses can update persistent adoption state and apply WiFi configuration through UCI. There is no internal threading or event framework; the main loop runs once per second. ## Source map | Concern | Start here | Responsibility | | --- | --- | --- | | Lifecycle and scheduling | `src/main.c` | Load config/state, choose model, run announce/inform/LLDP timers | | User configuration | `src/config.[ch]`, `files/openuf.conf` | Parse static daemon settings and defaults | | Persistent controller state | `src/state.[ch]` | Read/write `/etc/openuf/state.json` | | Inform exchange | `src/inform/inform.c`, `src/inform.h` | Orchestrate payload, TNBU, HTTP, and response stages | | Inform internals | `src/inform/{payload,packet,response}.c` | Build telemetry, encode TNBU packets, handle commands | | Transport and encryption | `src/http.[ch]`, `src/crypto.[ch]` | Raw HTTP/1.0 client and AES-CBC/AES-GCM helpers | | WiFi provisioning | `src/wlan/{provision,legacy,radio,uci}.c`, `src/wlan.h` | Translate controller config to UCI | | WiFi telemetry/helpers | `src/wlan/{telemetry,common}.c` | Report VAP state and share translations | | Device telemetry | `src/sysinfo.[ch]`, `src/clients.[ch]` | Read proc/sysfs/`iw`/bridge/dnsmasq data | | Discovery/topology | `src/announce.[ch]`, `src/lldp.[ch]` | UniFi UDP announce and LLDP send/read | | Emulated hardware | `src/models.c`, `src/ufmodel.h` | Model registry, radios, ports, and band-to-radio mapping | | Packaging/service | `Makefile`, `files/openuf.init` | OpenWrt package recipe and procd service | Runtime flow: `main()` -> `inform_send()` -> build telemetry -> encrypt -> `http_post()` -> decrypt response -> `inform_handle_response()` -> optionally `wlan_apply_config()`/`wlan_apply_system_cfg()` and `state_save()`. ## Important invariants - Treat the TNBU packet layout, byte order, flags, and key selection as protocol compatibility constraints. An unadopted device must use `DEFAULT_AUTH_KEY`. - `cfgversion` means successfully applied controller configuration. On an apply failure it is reset to `"0"` so the controller retries. - Increment `OPENUF_CONFIG_SCHEMA` when a persisted configuration must be reapplied after an upgrade. - Only WiFi sections managed by this daemon may be removed. Their names start with `openuf_`; preserve unrelated UCI sections. - Keep model-specific radio and port assumptions in `models.c`, not scattered across protocol or WLAN code. - Logging is opt-in because persistent writes wear flash. Debug level 2 may log decrypted credentials; never enable it by default or expose full auth keys. - This daemon runs as root and can change network config, send raw frames, and reboot. Do not run it on a development host as a test. - The target uses OpenWrt/musl and constrained hardware. Prefer bounded buffers, explicit ownership, no new heavy dependency, and no background thread unless the design requires one. ## Build and validation The primary validation is the package cross-build. From the OpenWrt root (two directories above this package), run: ```sh make package/OpenUniFi/compile ``` Use `V=s` when compiler diagnostics need more context. Avoid a top-level `make clean`; if a clean rebuild is necessary, use: ```sh make package/OpenUniFi/clean make package/OpenUniFi/compile ``` `Makefile.standalone` is for compiling on an OpenWrt device with development packages installed; it is not a host-side substitute for the cross-build. Architecture pages for the Gitea Wiki are generated from the recursive C source tree into a separate checkout. After source or architecture changes, run: ```sh ./scripts/docs/generate-wiki.py --output /path/to/openunifi.wiki ./scripts/docs/generate-wiki.py --check --output /path/to/openunifi.wiki ``` There is currently no automated test suite. For documentation-only changes, check paths and commands against the source and package Makefile. For C changes, the cross-build is the minimum verification; report any device/controller behavior that still needs manual testing. ## Change discipline - Keep headers as the concise contract and implementation detail in `.c` files. - Update `Makefile` and `Makefile.standalone` together when adding/removing a source file or library. - Update `files/openuf.conf`, `config.[ch]`, and the README together when changing a user-facing setting. - Update `ufmodel.h`, every affected model entry, and telemetry/WLAN consumers together when changing model data. - Preserve controller compatibility unless the task explicitly changes it. Call out changes to payload fields, encryption, adoption, UCI, or persistent state in the handoff. - Do not commit generated binaries, OpenWrt build output, runtime state, logs, or captured protocol payloads. ## Environment pitfalls and shared discoveries - In this workspace, the Codex `apply_patch` helper is currently unusable. It fails with `bwrap: No permissions to create a new namespace`, including when invoked from an approved command outside the normal sandbox. Do not spend time retrying it or tracing its symlink after seeing this known error. - For repository edits, use `git apply --recount` with a focused unified diff as the fallback. `--recount` avoids failures caused by manually miscounted hunk lengths. Review the resulting `git diff` and run `git diff --check` afterward. Preserve unrelated worktree changes exactly as with any other editing method. - Ordinary read-only commands may fail with the same `bwrap` namespace error. When the command is safe and required, rerun it using the environment's normal escalation/approval mechanism instead of investigating the namespace setup. - OpenWrt's release SDK host tools and preload libraries are x86-64. When using them through QEMU on an ARM runner, never export the SDK's fakeroot library as host `LD_PRELOAD`; carry it in a private variable and pass it to the bundled x86 loader with `--preload`. Validate changes with an emulated build through mbedTLS packaging, where a broken handoff appears as a `library/...` dependency. Agents must preserve useful environment knowledge for later agents. When a new pitfall or workaround is verified to be deterministic or repeatedly encountered, add a short entry to this section before handoff. Keep these entries actionable and specific: include the recognizable failure, the confirmed workaround, and any validation required afterward. Do not record transient command failures, guesses, lengthy logs, credentials, auth keys, host secrets, or details that only apply to a single task. If a discovery could weaken safety controls or requires broader permissions, report it to the user instead of documenting a bypass.