Files
OpenUniFi/README.md
T
Koda f5d14b0a79
Generate and publish developer Wiki / generated-wiki (pull_request) Successful in 14s
fixing wiki generation
2026-07-19 21:32:10 +00:00

184 lines
7.4 KiB
Markdown

# openUF
Daemon that makes an OpenWrt router appear as a UniFi AP to UniFi Network controllers.
## Implemented Features
| Feature | Description | Implementation |
| --- | --- | --- |
| **L2 Discovery** | UDP broadcast + multicast every 10s | `announce.c` → port 10001 |
| **Adoption** | AES-128-CBC/GCM handshake with the controller | `inform/response.c``inform_handle_response()` |
| **Remote reboot** | Reboots OpenWrt when requested by the controller | `inform/response.c``inform_handle_response()` |
| **Firmware spoofing** | Persists and reports the target version requested by an upgrade | `inform/response.c``inform_handle_response()` |
| **WiFi Config** | Creates WiFi networks from the controller via UCI | `wlan/provision.c``wlan_apply_config()` |
| **Band Steering** | 802.11k/v Neighbor Reports + BSS Transition | `wlan/provision.c` and `wlan/uci.c` |
| **Fast Roaming** | 802.11r FT with a stable SSID mobility domain | `wlan/provision.c``apply_vap()` |
| **WPA3 / PMF** | SAE, SAE-mixed, 802.11w 0/1/2 | `wlan/common.c` and `wlan/provision.c` |
| **WiFi Clients** | MAC, signal, bitrate, bytes per VAP | `clients.c``iw station dump` |
| **Wired Clients** | MACs from bridge FDB | `clients.c``bridge fdb` |
| **CPU / RAM** | Real-time usage | `sysinfo.c``/proc/stat` + `/proc/meminfo` |
| **Interfaces** | Speed, duplex, rx/tx counters | `sysinfo.c``/proc/net/dev` |
| **Channel / RF** | Channel utilization, noise, tx_power | `sysinfo.c``iw survey dump` |
| **LLDP Send** | Custom frames via AF_PACKET raw socket | `lldp.c``lldp_send_frame()` |
| **LLDP Read** | Neighbors for UniFi topology | `lldp.c``lldpctl -f json` |
## Building in the dev container
```shell
# From the OpenWrt build root
cd /home/openwrt/openwrt
# Build only this package
make package/OpenUniFi/compile
# For a clean package rebuild
make package/OpenUniFi/clean
make package/OpenUniFi/compile
```
`Makefile.standalone` is an alternative for compiling directly on an OpenWrt
device that has the development dependencies installed:
```shell
make -f Makefile.standalone
```
Contributors and AI agents should read [`AGENTS.md`](AGENTS.md) for the concise
architecture map, invariants, and validation checklist.
## Developer documentation and Gitea Wiki
The publish-ready pages live in the separate `Koda/openunifi.wiki` repository.
They include a developer guide, a generated Mermaid function-call graph, and
runtime flow charts. Check out that repository, then refresh it after source or
architecture changes:
```shell
./scripts/docs/generate-wiki.py --output /path/to/openunifi.wiki
```
Use the same tool as a linter to reject stale pages, oversized C modules,
missing documented entry points, or known non-English comment fragments:
```shell
./scripts/docs/generate-wiki.py --check --output /path/to/openunifi.wiki
```
The generator uses only the Python 3 standard library, and the publisher uses
POSIX shell utilities and Git. Neither downloads or executes an x86-only helper,
so both run natively on ARM and x86 build agents.
Publishing is an explicit authenticated step: `./scripts/docs/publish-wiki.sh`.
The script derives the lowercase `.wiki.git` repository URL from `origin`,
checks it out before generating, and accepts an explicit URL override. No
credentials are stored in this repository. The documentation workflow performs
the same two-checkout process and requires `GITEA_TOKEN` to have write access to
`Koda/openunifi.wiki`.
## Automated releases
Every push to `main` runs `.gitea/workflows/release.yaml`. It builds with pinned
OpenWrt SDKs and publishes `openUniFi-<architecture>-<version>.apk` for x64,
x86, arm64, arm32, and mpc85xx. The workflow uses Gitea's built-in
`GITEA_TOKEN`; repository Actions settings must allow it `write` access to
releases. A failed target leaves the release as a draft rather than publishing
an incomplete set.
Targets and the pinned OpenWrt release live in `.gitea/release-targets.json`.
Add an object with a unique `architecture` label and a valid OpenWrt
`target`/`subtarget` pair to extend the build list; no workflow change is
required. The generic ARM entries select ARMv7 and ARMv8 ABIs; use a
device-specific OpenWrt target when necessary.
OpenWrt publishes its release SDKs with x86-64 host tools, even when the target
is ARM or PowerPC. On an ARM build agent, the workflow installs
`qemu-user-static` and the build script runs the SDK host tools explicitly
through `qemu-x86_64-static`; privileged `binfmt_misc` registration is not
required. Native x86-64 agents skip emulation and remain faster.
Releases use the next available `MAJOR.MINOR.PATCH` tag. `MAJOR` and `MINOR`
live in the release config; the workflow finds the highest existing
`vMAJOR.MINOR.PATCH` tag and increments its patch, starting at `0` when a new
major or minor line is introduced. For example, changing the config from `0.4`
to `0.5` makes the next release `0.5.0`. Release runs are serialized so two
merges cannot select the same patch version.
Alternatives are Conventional Commits with a semantic-release tool (best when
not every merge must release), or a manually maintained `VERSION` file bumped
in every pull request (simple, but a forgotten bump blocks the release). Change
`major` for incompatible changes and `minor` for compatible features.
## Changing Compiler Settings
```shell
# OpenWRT build directory
cd /home/openwrt/openwrt
# Change settings
make menuconfig
# export settings
./scripts/diffconfig.sh
# Paste settings into .devcontainer/openwrt.config file in the code
# Then rebuild the dev container by pressing F1 in VScode
# and typing rebuild and selecting rebuild dev container
```
## Configuration
On the access point, run the following to install the package:
```shell
# Install dependencies
# replace wpad-basic-mbedtls with wpad-mbedtls
apk del wpad-basic-mbedtls && apk add wpad-mbedtls && /etc/init.d/network restart
# Remove old installation
apk -r del openuf
# Install new version
apk add openuf-0.4.0-r3.apk --allow-untrusted
# Configure
vi /etc/openuf/openuf.conf
```
Example Configuration
```ini
controller_ip = # Empty: use IPv4 default gateway
lan_if = br-lan # Default Lan interface Name
ufmodel = u6-inwall # emulated model
inform_interval = 10 # inform interval
enable_announce = 1
enable_inform = 1 # Enable adoption and telemetry requests
enable_logging = 1 # Write diagnostics to /var/log/openuf.log
protocol_debug_level = 0 # 0=off, 1=safe response details,
# 2=full decrypted JSON (contains secrets)
```
Set `controller_ip` to a controller IPv4 address or hostname to override
autodetection. The automatic mode uses the IPv4 default-route gateway for
initial adoption; after adoption, the controller-provided inform URL is kept.
Daemon settings live in `/etc/openuf/openuf.conf`. Adoption and controller state
are persisted separately in `/etc/openuf/state.json`; do not copy that file
between devices because it contains the device authentication key.
Because UniFi firmware cannot run on the OpenWrt host, an upgrade request does
not download or install its image. Instead, openUF saves the requested firmware
version in `state.json` and reports it in subsequent inform packets.
---
## Glossary
### TNBU
TNBU is the magic string/identifier at the start of the binary packet format used in this custom Inform protocol implementation.
### CCQ
Client Connection Quality