Brighton's Blog
← All Series

OpenWrt

1 - Installing OpenWrt on a Meraki MR18

MerakiMR18RouterJTAGOpenWrt

This is my first blog—I am not very proficient in writing, especially not technical writing and my grammar sucks, but hey who cares. I will have a series of posts talking about how I managed to install OpenWrt on a Meraki MR18 access point. I will try to explain things as I go to not leave readers in the dark, but some background technical understanding/ability to research more in-depth confusing topics will greatly help the reader.

Read more →

2 - Installing OpenWrt on a Meraki MR18

MerakiMR18RouterJTAGOpenWrt

I mean, where the fuck should I really even start?

I got hoes that I’m keepin’ in the dark — Drake ft. Rick Ross, “Money In The Grave”

Okay, but really though, where do I start? Right now we know that the Meraki MR18 is cloud-locked by Cisco. Without an active Meraki dashboard license there are many niceties that I don’t have access to such as:

Read more →

3 - Installing OpenWrt on a Meraki MR18

MerakiMR18RouterJTAGOpenWrt

Everything is wired up, let’s flash

She said, “Where we goin’?” I said, “The moon” — Travis Scott, “SICKO MODE”

Alright so we left off with all the wires connected, the bench power supply ready, and my ESP-Prog looking like a spaghetti monster grew on my desk. Time to actually make this thing do something.

Read more →

4 - Installing OpenWrt on a Meraki MR18

MerakiMR18RouterJTAGOpenWrt

The cache coherency nightmare and other fun MIPS things

I be going through some things, you don’t know what I’ve been thinkin’ — YG ft. Kendrick Lamar, “Really Be (Smokin N Drinkin)”

Read more →

5 - Installing OpenWrt on a Meraki MR18

MerakiMR18RouterJTAGOpenWrt

Five approaches to pressing a button (and a ghost from Cisco)

I know you’re somewhere out there, somewhere far away — Bruno Mars, “Talking to the Moon”

Okay so the kernel booted. Like actually booted. I saw Linux version 6.6.73 scroll across the UART console. The CPU was running, the scheduler was active, idle task spinning. I set up my host Ethernet at 192.168.1.2/24, pointed my browser at 192.168.1.1, and… nothing. Ping? Nothing. Telnet? Nothing. ARP? Nothing.

Read more →

6 - Installing OpenWrt on a Meraki MR18

MerakiMR18RouterJTAGOpenWrt

The last mile: a PHY bug and a 20-minute serial transfer

Crocodile leather patches, baby, oh (We made it on our own) — Yeat ft. EsDeeKid, “Made It On Our Own”

Read more →

7 - MR18 Deep Dive: Hand-Encoded MIPS Assembly

MerakiMR18MIPSAssemblyJTAGOpenWrtdeep-dive

Encoding instructions by hand like it’s 1985

Post 4 mentioned that I hand-encoded every MIPS instruction as hex constants directly in Python. Here’s what that actually looks like in practice—every trampoline, every encoding decision, and the one-bit typo that almost ruined everything.

Read more →

8 - MR18 Deep Dive: Talking to Hardware

MerakiMR18PythonJTAGOpenWrtOpenOCDdeep-dive

The plumbing

I got my mind on my money and my money on my mind — Lil Wayne, “Money On My Mind”

Every previous post in this series focused on the dramatic stuff—cache coherency nightmares, hand-encoded MIPS assembly, twenty-minute UART transfers. But none of that works without the plumbing. The mr18_flash.py script has about 300 lines of infrastructure code that handles three things: talking to a bench power supply, talking to OpenOCD over telnet, and managing the OpenOCD process itself. It’s not glamorous. It’s the kind of code you write at 1am because you’re tired of manually typing commands into four different terminals. Let’s walk through it.

Read more →

9 - MR18 Deep Dive: The Timing Attack

MerakiMR18PythonJTAGOpenWrtEJTAGdeep-dive

Catching a CPU in the dark with a 1.5 second flashlight

The selfish are constantly profitin’ off the helpless — Denzel Curry, “Walking”

Post 3 gave the high-level overview of the timing attack—power on, wait 1.5 seconds, halt the CPU before Cisco’s kernel murders the JTAG interface. This post rips open mr18_flash.py and walks through every halt strategy and the main retry loop in detail. None of this is elegant. It’s the kind of code you write at 2am when you’ve already power-cycled an access point forty times and you’re starting to take it personally.

Read more →

10 - MR18 Deep Dive: Loading and Flushing

MerakiMR18PythonJTAGOpenWrtcachedeep-dive

What load_and_run() actually does (phases 0-2)

I’m a prophet, don’t take shit, won’t harm shit — Samara Cyn, “Sinner”

Posts 3 and 4 gave the high-level overview of the load pipeline—flush, load, flush again, verify, launch. This deep-dive series rips open the actual Python and walks through the code. We’re starting with phases 0 through 2 of load_and_run(), which covers everything up to but not including the XOR verification passes.

Read more →

11 - MR18 Deep Dive: Verification

MerakiMR18PythonJTAGOpenWrtMIPSdeep-dive

CPU-executed XOR verification

Post 10 covered phases 0 through 2—flush, load, flush again. At that point we have 6.9 MB of initramfs sitting in DRAM, and now we need to answer a simple question: is it correct? This post covers phase 3, the XOR verification pipeline, including the approach that didn’t work and the one that does.

Read more →

12 - MR18 Deep Dive: Launch and Failsafe

MerakiMR18PythonJTAGOpenWrtUARTdeep-dive

Launching the kernel and catching failsafe on the way down

Lotta different problems, you would think they came with lessons — AVGUST, “Vanilla Latte”

Post 10 ended with a verified binary in clean DRAM. Post 5 gave the high-level failsafe saga. This post covers the actual code: the launch trampoline, the regression that taught me to stop touching the CPU, and two competing strategies for triggering failsafe mode.

Read more →

13 - MR18 Deep Dive: Network and Sysupgrade

MerakiMR18PythonOpenWrttelnetdeep-dive

Network setup and sysupgrade

They won’t leave in the night. Have no fear that they might desert me — Kanye West ft. JAY-Z, “Diamonds From Sierra Leone”

Twelve posts deep. Cache flushes, MIPS trampolines, XOR verification, UART monitoring, failsafe timing. This post covers the last mile—once the kernel is booted and failsafe is confirmed, how do we talk to the device over the network and flash the permanent sysupgrade image? No more PRACC, no more cache paranoia. Just TCP/IP and a couple of file transfers.

Read more →

15 - MR18 Deep Dive: UART Scripts

MerakiMR18PythonUARTOpenWrtdeep-dive

Hex-encoding 7 million bytes because the PHY won’t cooperate

Post 6 described the hex-over-UART transfer protocol at a high level—hex-encode every byte, pipe it through an awk decoder on the MR18, pray nothing goes wrong for 20 minutes straight. This post rips open send_binary.py and uart_transfer.py and walks through the actual Python. Two scripts, two transfer sizes, same dumb protocol, very different engineering challenges.

Read more →