Build and publish release / metadata (push) Canceled after 0s
Build and publish release / create-release (push) Canceled after 0s
Build and publish release / build (push) Canceled after 0s
Build and publish release / publish-release (push) Canceled after 0s
Generate and publish developer Wiki / generated-wiki (push) Failing after 43s
Reviewed-on: #38 Co-authored-by: Koda YeenBean <n122330@gmail.com>
184 lines
7.4 KiB
Markdown
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 |