Adding OpenWrt support for Xiaomi "Redmi Router AX6S"/"Xiaomi Router AX3200"

Xiaomi at it again with their... 10th? 802.11ax router design. Not to be confused with the similarly named AX6, which is a Qualcomm based solution, this is a MediaTek MT7622B design.

Teardown on Chinese review site:


  • SoC : MediaTek MT7622B
  • RAM : DDR3 256 MiB (ESMT M15T2G16128A)
  • Flash : SPI-NAND 128 MiB (ESMT F50L1G41LB)
  • WLAN : 2.4/5 GHz 4T4R
    • 2.4 GHz : MediaTek MT7622B (bgn only, likely 256-QAM capable)
    • 5 GHz : MediaTek MT7911AN (Chip markings say MT7975AN+MT7911AN, but drivers look like they're still looking for 7915 at start of eeprom, and even the DTS description refers to it as MT7915E?)
  • Ethernet : 4x 10/100/1000 Mbps
    • Switch : MediaTek MT7531B
  • LEDs/Keys : 2/2 (Internet + System LED, Mesh button + Reset pin)
  • UART : Marked J1 on board, next to reset. VCC RX GND TX starting from pin labelled 1. 1.8v3.3v, 115200n8 (Obviously don't connect VCC unless you want to fry things)
  • Power : 12 VDC, 1.5 A

Random notes:
Usual Xiaomi caveats apply here. Locked down bootloader and firmware.

EDIT: The below is crossed out for a reason, you will probably have more success using UART to glitch out the recovery sequence and having it fail-open the UART input if you have a telnet locked AX3200/RB01. See: Adding OpenWrt support for Xiaomi "Redmi Router AX6S"/"Xiaomi Router AX3200" - #513 by arch_pilot

If using a AX6S or RB03, just "acquire" the closed beta firmware image and flash that for access.
Will require either exploit on stock firmware or manipulating u-boot env with nand programmer. Dumping and modifying the spi-nand may be easier to pull off due to the unpopulated pads next to the installed spi-nand. (Chip appears to be supported by SNANDer, for those with CH341A

Sadly, the old extendwifi vulnerability present in earlier versions of the AX9000 is patched in the earliest firmware available. (I can see that they now sanitise the token input)

It however seems there is/was a image parsing bug in the mkxqimage binary of the other models though, so we'll see how that pans out.

Refer to the wiki for installation instructions:

Presumably this device will be of little interest to those who managed to acquire cheap E8450/RT3200, but this should be available globally (well, if you count grey-imports from Ali as global) for a non-ridiculous price.


Around 70 EUR incl. 19% would be pretty reasonable, especially considering the scarce availability of the rt3200. The big question would be about how locked down (secure boot, etc.) this device is and how many other hurdles come up, RAM could be a tad bigget though.2

I don't think I could verify this just by looking at the stock image

I suspect whomever does bring-up may also end up replacing u-boot or chainloading another u-boot because of similar ubifs compatibility issues like the other MT7622 devices.


If I'm looking at this correctly, Xiaomi don't actually sanitize the input for DDNS settings properly in their API for things that aren't the ips (ie. domain name, username, password).

Even stranger, it appears their version of ddns-scripts is too old to have the commit that would have sanitized out the shell escapes for them? Or rather, they have the version number of a release that should have some checking, but the actual content of that particular commit isn't present? I think they messed up the merge when they forked their own one to add chinese DDNS services?

So I guess api/xqnetwork/{ddnsEdit/add_server/} to insert uci config strings with escape characters and commands, then watching DDNS try to update.

I could be wrong though, someone else should verify the contents of


To confirm these findings.

It can't be that simple, right? ...right?

Edit: It wasn't. They put some sed magic at the beginning to sanitize this instead of using the method from master. Ignore this.

1 Like

Just ordered one of these routers based on this post, but it looks like it won't be arriving for a month or so potentially. In the meantime though I can help review the files for potential exploits.

Forgive my ignorance - how are you seeing the contents of those files? Are you like decompressing the Xiaomi firmware images, accessing them locally on the device, or are you looking at their code repositories directly?

Probably a mixture of binwalk -e …, ubireader_extract_images -o … and unsquashfs ….

1 Like

The uncoded sources are contained here:

The algorithm for parsing the HDR image format can be found here:

SquashFS (hsqs) images can be unpacked using the 7zip utility. But sometimes these HSQS images are diluted with UBI headings that should be removed.

To decode actual LUAC files, you need to use this tool:



Responsible disclosure policies render this post untenable, I'll keep the discussion strictly about porting OpenWrt from hereout.

Here's the partition layout since we're here:

root@XiaoQiang:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00020000 00020000 "PL_Header"
mtd1: 00060000 00020000 "Preloader"
mtd2: 00040000 00020000 "ATF"
mtd3: 00080000 00020000 "uboot"
mtd4: 00040000 00020000 "Nvram"
mtd5: 00040000 00020000 "Bdata"
mtd6: 00080000 00020000 "Factory"
mtd7: 00040000 00020000 "crash"
mtd8: 00040000 00020000 "crash_log"
mtd9: 01e00000 00020000 "firmware"
mtd10: 002a0000 00020000 "kernel"
mtd11: 01b60000 00020000 "rootfs"
mtd12: 01e00000 00020000 "firmware1"
mtd13: 03200000 00020000 "overlay"
mtd14: 00500000 00020000 "obr"

Not a very efficient layout. Obvious change would be to just merge overlay and obr like on the other Xiaomi device ports. Doing more would probably require some u-boot finesse or replacement like the E8450.


It turned out that Xiaomi divided the Chinese version from the global one at the level of firmware and the name of the "hardware".
The internal name of the global model is RB01, and the Chinese name is RB03. Previously, such a division was simply at the level of the region specified in the Nvram/BData partition.

We get this division:

  1. Internal name: RB01
    CPU: MT7622B
    displayName: Mi Router AX3200
    Device card:
  2. Internal name: RB03
    CPU: MT7622B
    displayName: Redmi 路由器 AX6S
    Firmware list:

It is very likely that this was done precisely for the impossibility of flashing the firmware inappropriate for the region, since this check is built into the bootloader and the mkxqimage tool.

PS. Seemingly like a global router: (RB01)

Yeah, it should make it impossible to accidentally tftp recover cross-region or directly have mkxqimage flash the images without patching the binaries involved?

Also something annoying that I noticed...

The LAN/WAN mac addresses only seem to exist within the bdata partition.

ethaddr_lan=$(bdata get ethaddr)                                                                                                                                                                                                                                                                                                                                                         
ethaddr_wan=$(bdata get ethaddr_wan)

So I have to setup the dual u-boot env partitions and set the macs in 02-network as opposed to the dts.

Oddly enough, Xiaomi are advertising the MT7622B CPU as a FiLogic800, the only place on the internet where anyone is calling it such? I've edited the thread title as such, and added the "Xiaomi Router AX3200" as a variant. (Does this make the global version name the Xiaomi Xiaomi Router AX3200 in OpenWrt? That sounds weird.)

FiLogic 130 = mt7931
FiLogic 330 = mt7921/mt7922
FiLogic 630 = mt7916
FiLogic 800 = mt7622
FiLogic 830 = mt7986


While the teardown on the chinese site was helpful, they managed to write down the wrong voltage for the UART.

It's 3.3v, not 1.8v. If you wonder why only your RX is working...

Not sure what's up with my Internet LED though, it's both on for some reason (purple).


Check the LEDs in the DTS file? or maybe you just need to set it with the 01_leds

@namidairo thinking about buying one :grinning:
How did you manage to get root access?
And which of the hardware versions would you recommend, the global or Chinese one?

Oh right, I had them set to GPIO_ACTIVE_HIGH instead of GPIO_ACTIVE_LOW... All the on/off were inverted :slight_smile:

I did also put the wan led into 01_leds now, thanks for reminding me.

I actually did that too. I hope we can put owrt easily.

so mine arrived. it turned out that telnet is enabled in my router by default. password for root can be genrated using script from this page.
overall what are the chances to get working openwrt on this router?

I tried telnet once or twice when trying to get in without success, I suspect that the factory defaults in nvram/uboot-env are looser than usual for qualification tests or something, then are set back to zero on first boot. I recall similar things being mentioned on the Redmi AC2100.

I would have assumed they would move the firstboot script earlier on so it wouldn't run after the service init scripts, but I guess not?

Highly recommend you take this chance to telnet in and nvram set telnet_en=1, nvram set uart_en=1, nvram set ssh_en=1 (well, you'd still have to modify the init script to ignore the fact that you're running release channel firmware, but the contents of mine would reset on each boot so I think you'd have to put it in the overlay somehow), nvram set boot_wait=on, nvram commit etc; before you lose access. (Worst case scenario you would have serial access to u-boot with these all on.)

Yeah, I slightly modified the python implementation that was floating around because it had some weird dependency and expected a file, even though punching in the serial from the sticker/web ui was fine. I'll paste it below for reference, since many would prefer a python implementation.

#!/usr/bin/env python3
import sys
import hashlib

if sys.version_info < (3,7):
    print("python version is not supported", file=sys.stderr)

# credit goes to zhoujiazhao:

salt = {'r1d': 'A2E371B0-B34B-48A5-8C40-A7133F3B5D88',
        'others': 'd44fb0960aa0-a5e6-4a30-250f-6d2df50a'}

def get_salt(sn):
    if "/" not in sn:
        return salt["r1d"]

    return "-".join(reversed(salt["others"].split("-")))

def calc_passwd(sn):
    passwd = sn + get_salt(sn)
    m = hashlib.md5(passwd.encode())
    return m.hexdigest()[:8]

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print(f"Usage: {sys.argv[0]} <S/N>")

    serial = sys.argv[1]

Most likely you have factory mode activated. It is in this mode that devices are flashing. And it is in this mode that the telnet is forcibly turned on.
To check the activated factory mode, run the following query:

will check that, @namidairo - do you have any build that you can share? I saw screenshot - is that yours?