OpenNGFW: Linux for a Netgear R6300v2
OpenNGFW: Turning an Old Netgear Router into a Next-Gen Embedded Linux Appliance
It all started with a very specific, practical problem. My girlfriend has a collection of retro handhelds and consoles, and I wanted a dedicated VPN appliance sitting on her local network that could automatically sync her save files and ROM states back to my self-hosted Syncthing server.
I had an old Netgear R6300v2 sitting in storage. It had decent bones for an embedded Linux box: a dual-core Broadcom BCM4708 ARMv7 Cortex-A9 processor, 256MB of RAM, Gigabit Ethernet, and USB 3.0 ports. In the early planning stages, I gave the project the working code name "Anbergear"—a quick mashup of Anbernic and Netgear for what was supposed to be a simple VPN bridge.
As I started digging into the hardware and stripping away the vendor junk, the scope grew. What was originally meant to be a simple Syncthing tunnel quickly turned into an ambitious project: building OpenNGFW, a ground-up, modern embedded Linux distribution, firewall, and modular package ecosystem for the Netgear R6300v2 (with future support planned for devices like the R7000 Nighthawk).
Here is the story of how OpenNGFW came together, from UART console hacking with a Raspberry Pi Pico to wrestling with ancient Broadcom bootloaders and writing a custom package manager from scratch in V-lang.
1. Hardware Debugging: Using a Raspberry Pi Pico as a UART Bridge
To do bare-metal development on a router without turning it into a plastic brick, a hardware serial console is non-negotiable.
The Netgear R6300v2 PCB exposes a 4-pin UART header (3.3V, TX, RX, GND). Rather than waiting weeks for an AliExpress shipment with dedicated USB-TTL FTDI dongles to arrive, I grabbed a spare Raspberry Pi Pico sitting on my workbench. By flashing the pico-uart-bridge UF2 firmware onto the RP2040, the Pico becomes a dedicated, rock-solid 3.3V USB-to-UART serial converter.
(Raspberry Pi Pico running pico-uart-bridge firmware wired directly to the router's UART header)
After connecting GND to GND, Pico TX (GP16) to Router RX, and Pico RX (GP17) to Router TX, I plugged the Pico into my PC over USB and opened up picocom:
picocom -b 115200 /dev/ttyACM0
Powering on the router and interrupting the boot sequence brought up the Broadcom CFE (Common Firmware Environment) bootloader prompt:
CFE version 1.0.37-111.139 for BCM947XX (32bit,SP,LE)
Build Date: Tue Sep 10 16:15:32 CST 2013
Init Arena
Init DMA
Init Ethernet
CFE>
With direct access to the bootloader, memory registers, and flash controller, development could begin.
2. Bootloader Challenges: Booting Modern Linux on Broadcom Silicon
Broadcom's BCM4708 / BCM5301X platform is notoriously finicky when it comes to booting upstream Linux kernels. CFE is a legacy bootloader designed around specific vendor assumptions and expects firmware images packed in a proprietary TRX container format.
(Watching early kernel initialization over the Pico serial link)
Appended Device Trees & TRX Images
- Device Tree Appending: Modern ARM kernels require a Flattened Device Tree (
bcm4708-netgear-r6300-v2.dtb) to map hardware peripherals, switch ICs, and LEDs. Because CFE does not support passing a separate DTB pointer in RAM during TFTP or flash boots, the kernel neededCONFIG_ARM_APPENDED_DTB=y. The compiled DTB binary is appended directly to the end of thezImagepayload so the kernel can parse its own hardware description at boot. - Container Packaging with
otrx: To construct a valid image that CFE's validation routines accept, we usedotrxto assemble the kernelzImage(with appended DTB) and the squashfs root filesystem into aligned TRX partitions:otrx create openngfw-r6300v2.trx -f zImage-dtb -a 0x1000 -f rootfs.squashfs - Early Printk Debugging: Early test builds produced complete silence after CFE jumped to execution address
0x8000. By enabling low-level debugging (CONFIG_DEBUG_LL) targeted directly at the BCM5301X UART MMIO base register (0x18000300), we could view early kernel panics and resolve timer initialization issues before the standard 8250/16550 serial driver took over.
Once configured, both Cortex-A9 cores came online cleanly, initializing the Gigabit switch and NAND flash controllers.
3. Designing OpenNGFW: Buildroot, Musl Libc, and Storage Architecture
Rather than stripping down a general-purpose Linux distribution, OpenNGFW is built using Buildroot paired with musl libc. This keeps the base operating system footprint minimal—idling at around 35MB of RAM.
(OpenNGFW logged into the Zsh shell with hardware resource metrics)
Key architectural choices in OpenNGFW include:
- Read-Only Rootfs with Persistent USB Storage: The primary root filesystem is stored in a compressed read-only SquashFS image in flash. For installing software and storing persistent data, an external USB drive is mounted at
/mnt/usb/opt. - Interactive Terminal Environment: The default user environment is configured with Zsh, powerline glyphs, execution timers, and clean ANSI dark-mode formatting.
- Network Stack: Native bridge (
br0) setup for LAN ports, automatic WAN DHCP provisioning, and hardware NAT routing.
4. Building ngpkg: A Dedicated Package Manager in V-Lang
With a working base system, the next challenge was application delivery. Embedded flash storage is limited, and cross-compiling every application directly into the base firmware image slows down development iteration.
To solve this, I designed and built ngpkg (invoked on the router simply as pkg), a standalone package management suite written in V-lang.
(Running pkg list and installing packages with ANSI box formatting and download progress)
Why V-lang?
V is well-suited for embedded systems: it compiles down to clean, single-binary C99 code with zero external runtime dependencies, has safety and high performance, and allows rapid iteration.
Package Architecture
The ngpkg ecosystem consists of three parts:
- Client (
client/ngpkg.v): A fast CLI that handles syncing repository metadata, downloading compressed.ngpkgarchives, extracting payloads to/mnt/usb/opt, linking binaries to~/.ngpkg-bin/, and executing router lifecycle hooks (install.sh/uninstall.sh). - Streaming Server (
server/pkg_server.v): A lightweight HTTP daemon written in V that serves package repositories using 64KB chunked buffered socket streaming, provides REST API health endpoints (/api/health), and hosts a web dashboard. - Recipe Build System (
framework/ngpkg_build.py): A modular build framework that builds standalone recipes (recipe.json+build.sh) against the ARMv7 musl toolchain and publishes updatedindex.jsonandindex.txtrepository indexes.
5. Next Steps
OpenNGFW has grown from a simple VPN sync experiment into a solid embedded Linux platform for the Netgear R6300v2.
The next milestones for the project:
- Porting OpenNGFW to additional Broadcom ARM routers, starting with the Netgear R7000 (Nighthawk).
- Implementing a web-based administrative dashboard for interface configuration, firewall rules, and package management.
- Expanding package recipes to include Python 3 runtime, Redis, and Caddy reverse proxy.
The source code and build systems are hosted on my personal git instance: