Support for TP-Link EAP225 Outdoor v3

Unfortunately, neither of these improved the speed.

so.. I'm an idiot and flashed the v3 snapshot when I have a eap225-outdoor v1

it boots and flashes lights but I cant seem to access anywhere... does anyone have suggestions on how I could fix it?

Thanks for this post it was incredibly useful! I bought this thinking it could do a client mode and then discovered it could not with the stock firmware. I found this thread and used your post to flash openwrt. Using this to bridge my neighbor's Starlink at the cottage and it's working even better than I had hoped. Cheers!

1 Like

Glad to be of help

Just received my EAP225-Outdoor v3 today, it shipped with the 5.10 firmware..

When I try to upload the snapshot OpenWRT firmware, I get a "Failed to check for new update".. If I try to upload the official D-link 5.0.6 firmware, I get the same error.. So it seems like it sees the OpenWRT firmware as a downgrade..

What to do?


You should be able to access the serial console by opening the AP. Remove the antennas, unscrewing the securing nuts on the antenna connecters, and then pushing on the antenna connectors until the PCB slides out. At this point you should be able to find four pads labelled Ground, Vcc(?), Tx and Rx. Soldering wires to these four pads will allow you to connect to the serial console with an appropriate USB to serial adapter. I don't know exactly what comes next as I haven't gotten serial console access yet but I'll try to do a more detailed write-up with photos once I have the chance to sit-down and actually do the soldering myself.

EDIT: The serial console should allow you to interrupt the boot process and flash an image over ethernet via TFTP.

I was able to get serial and use "Ctrl + B" to interrupt the boot process but each time I try to flash something to "0x81000000" and run "bootelf" I get an error claiming that no elf exists at "0x81000000" so I'm kinda stuck now because neither the stock TP-Link firmware or OpenWRT will boot from "0x81000000."

I'm following the guide here (this guide is for EAP225-Outdoor v1 but should still, mostly, apply):

Anyone have any ideas on what to do once I have serial?

Sorry to triple-post but I think my progress warrants it!

I managed to figure out what I was doing wrong:
Once you have access to the serial port you need to flash an initramfs image over tftp to 0x80800000 which will allow you to boot into openwrt with the bootelf command. From this point you flash a sysupgrade image via openwrt. Then, once you reboot, you'll have access to openwrt without any further complications!

To clarify, the first part of the initramfs process doesn't modify anything in flash. The image only exists in RAM. Addresses that start with 8 are in the unit's RAM. That is why nothing exists there when first powered on.

@MrMEEE I find myself in the same position.

I did have success dropping back to 5.0.8 downloaded from, but the release notes on that say:

"3. After install this firmware, the EAP will not be able to install lower versions of firmware."

So, that is likely the culprit.

I'm digging in to the source to see how the factory.bin is packaged and if there is some version number I can change, kick off a rebuild, and I can then submit a PR.

The firmware version number can be updated in the tplink-safeloader.c sources of the firmware-utils repository. You could update the original sources, generate a patch (for submission) and drop that in the tools/firmware-utils/patches directory for testing.

1 Like

So I have (or had?) an EAP225-Outdoor v1 and v3. I noted that OpenWRT 23.05 rc2 is out and that the firmware builder claims support.

I adjusted the packages I wanted and uploaded to the v1. All went well, but then I thought of some other packages I'd like to have in my base build. Did a re-spin and uploaded the new build via LuCI. The v1 unit is now bricked (green flash, amber flash, steady green for ~5 sec - repeat).

I've been having odd behavior from the v1 lately so didn't worry too much about this. Did the same cycle with the v3 unit. Aaaand ... now bricked.

The repeatable pattern seems to be:

  • Upgrade to new OpenWRT build/version via LuCI
  • Wait for reboot
  • Upgrade to same OpenWRT version via LuCI
  • Wait for reboot... Observe I now have an anchor

I'm not sure I have the fine motor skills or patience to solder the pads and break in with a serial connection, so I suspect these two units are now anchors.

So why this post? To let others learn from my failure.

I cannot help with the patience aspect, but a PCBite might help with hitting the pads - no soldering required.

I had no idea the PCBite existed. That's awesome! But spendy. Ooof. The cost of both these APs.

If I did more hardware projects ...

Yeah, it is quite spendy. I only have one because my boss sent me one for work.

Tried this, it did not work. More specifically, it produces the same error "Failed to check for new update" as the current snapshot does.

I used the following patch, placed in tools/firmware-utils/patches/ as directed:

From e2fc7e872f8308da67216f6ea080476d51aaa819 Mon Sep 17 00:00:00 2001
From: Matthew Caron <>
Date: Sat, 1 Jul 2023 21:20:41 -0400
Subject: [PATCH] Set version number for TP-Link EAP225-OUTDOOR v3.

 src/tplink-safeloader.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tplink-safeloader.c b/src/tplink-safeloader.c
index 53a42f7..c76964a 100644
--- a/src/tplink-safeloader.c
+++ b/src/tplink-safeloader.c
@@ -1982,7 +1982,7 @@ static struct device_info boards[] = {
                        "EAP225-Outdoor(TP-Link|UN|AC1200-D):3.0 CA,JP\r\n",
                .part_trail = PART_TRAIL_NONE,
-               .soft_ver = SOFT_VER_DEFAULT,
+               .soft_ver = SOFT_VER_NUMERIC(5, 1, 0),
                .soft_ver_compat_level = 1,
                .partitions = {

This mirrors what was done in commit ef8ea36ef531b87bd208a370fc5dd4979d9c4321, but does not work here.

Either that or I messed up the build somehow, but the menuconfig was pretty clear and the resulting firmware was openwrt-ath79-generic-tplink_eap225-outdoor-v3-squashfs-factory.bin, so unless I need to do something to enable patch application from that directory, I'm not sure what's going on.

Somewhat interestingly - when I tried to verify that I can flash TP-Link version 5.1.0 over 5.1.0, it reports "The version is the same as the running firmware", which suggests that the version needs to be greater than 5.1.0 once we can figure out where the version information that it is looking for is.

If you have any ideas, I'll be glad to try them, but in a day or so I'm going to have a free evening and will just be grabbing the UART headers and flashing via the bootloader.

I have an EAP225 v4 with 5.1.0 and tried the same thing by specifying version 5.1.1 but I got the same result. I did a binary comparison of version 5.1.0 with my own image and I noticed that the partition layout is a little different, the soft-version and support-list partitions are swapped:

fwup-ptn partition-table base 0x00800 size 0x00800
fwup-ptn support-list base 0x01000 size 0x000fb
fwup-ptn soft-version base 0x010fb size 0x00018
fwup-ptn os-image base 0x01113 size 0x144458
fwup-ptn file-system base 0x14556b size 0x5fb000

fwup-ptn partition-table base 0x00800 size 0x00800
fwup-ptn soft-version base 0x01000 size 0x00018
fwup-ptn support-list base 0x01018 size 0x000d5
fwup-ptn os-image base 0x010ed size 0x236840
fwup-ptn file-system base 0x23792d size 0x430004

Maybe that's not a problem. Later on in the image the data for those two partitions are indeed in a different order. The 24 bytes of soft-version are after the support-list in 5.1.0 and before support-list in openwrt. This is the hex data for both soft-versions:

00 00 00 10 00 00 00 00 FF 05 01 00 20 22 09 26 00 00 F3 F8 00 00 00 02

00 00 00 10 00 00 00 00 FF 05 01 01 20 23 06 26 00 00 5B 9C 00 00 00 01

The pad1 (FF), version_major(05) version_minor(01) and version_patch(01) look good. The year_hi(20) year_lo(23) month(06) day(26) are also ok.
Next is the rev (00 00 5B 9C), not sure what thats about. compat_level (00 00 00 01) looks wrong. I changed that to 2 (.soft_ver_compat_level = 2). After that it accepted the file and went through the flashing process from the GUI.

Here's an updated tplink-safeloader patch if someone wants to clean it up and do something with it:

--- firmware-utils-2023-05-18-02cdbc6a/src/tplink-safeloader.c	Fri Jun 30 08:35:40 2023
+++ firmware-utils-2023-05-18-02cdbc6a/src/tplink-safeloader.c	Thu May 18 01:01:59 2023
@@ -1898,7 +1898,7 @@
 			"EAP225-Outdoor(TP-Link|UN|AC1200-D):3.0 CA,JP\r\n",
 		.part_trail = PART_TRAIL_NONE,
-		.soft_ver = SOFT_VER_DEFAULT,
-		.soft_ver_compat_level = 1,
+		.soft_ver = SOFT_VER_NUMERIC(5, 1, 1),
+		.soft_ver_compat_level = 2,
 		.partitions = {

The patch looks fine. You could use the firmware-utils binary to validate that the factory image contains the intended version number.

The console normally gives a more useful error message when a firmware image is rejected, which could help diagnosing the problem you're facing and how to solve it.

The partition order in the firmware upgrade file is arbitrary and doesn't matter. The partition table determines which parts go where in flash. Interesting to see they've bumped the compatibility level. First time I see it at 2 :slight_smile:

TP-Link's firmware image for the EAP225v4 contains the following device list:

EAP225-Outdoor(TP-Link|UN|AC1200-D):3.0 CA,JP
EAP225(TP-Link|UN|AC1350-D):4.0 CA

That means a single image could probably support all these devices, as the hardware must be near identical.

1 Like

@svanheule I can confirm that the patch from @mudlark does indeed create a firmware image that can be flashed using the stock 5.1.0 firmware.

However, my personal build of firmware that I flashed decided to hang at:

[    8.864964] random: ubusd: uninitialized urandom read (4 bytes read)

I TFTP-ed in an initramfs from the same build and, predictably, the result was the same.

So, in the end, I had to flash in a snapshot build anyway. BUT, we did validate that the packaging works if someone wanted to update the snapshot build to fix it.

Thanks for the help!