As I have mentioned in the review, the stock firmware on the Xiaomi AX3600 wireless router is extremely limiting. On top of that, the firmware is also locked to install only authorized updates from the manufacturer. If you have been following the blog, you will know that I like the flexibility that ASUSWRT provides for customizing my router.
While there is currently an on-going effort to try and port vanilla OpenWRT for this router, I suspect that might take some time. In this post, I describe how to workaround the lousy firmware and configure the router with the advanced features I need.
It is recommended to have UART access handy, in case something bad happens and you need to recover your router, or if you want access to U-Boot, the bootloader. This would require you to crack open your router, so you might only want to do this if necessary. Feel free to skip this section if you are not interested in the hardware, or don’t need low-level access.
You need to unscrew 5 screws, 4 of which are hidden under the rubber feet, and one under the center sticker label. In the disassembled top view photo here, you can see the screw holes at the corners, as well as a missing chunk in the center of the heatsink for the mating screw post, directly aligned with the AIoT antenna and indicator LEDs.
The clips that hold the two halves in place are the trickiest. I tried my best, but still managed to destroy some clips and a few plastic nubs after excessive prying. The clips are located all along the front and back of the case, as well as at the sides (where the two antennas are). If I were to do this again, I’d advise to start from the side clips because they don’t have any other obstructions. The front & back rows have additional plastic nubs that prevent the top cover from being squeezed inwards easily to release the clips, whereas these aren’t present at the sides.
You can check out more disassembly photos in my Flickr album, to hopefully help you avoid the mistakes I made.
The serial header is located at the left side of the board, with the unit facing towards you, antennas behind. I typically don’t like to solder down the header pins, so I taped the serial cable down to the metal plate to try and keep the header pins in place with friction.
They have also helpfully marked the colour of the cables if you are using the typical Chinese UART-to-USB adapter: green, white and black. The serial settings are typical: 115,200 baud, 8N1.
Note that you can only interrupt the boot sequence if you have
boot_wait=on set in the NVRAM.
Getting a Shell
You need to first get SSH access on the router, which is what some might call “jailbreaking”. This is done using an exploit found by others on the 1.0.17 version. I will not repeat the instructions here, but you essentially need to access a few URLs to
/etc/init.d/dropbearfor unconditional SSH access
- set a root password
- start the dropbear service
Later versions do not seem to have any known exploits. But if we just stick to this old version, we won’t get the benefits of newer versions, like 160MHz bandwidth or improved wireless drivers.
While there are people working on porting vanilla OpenWRT to the AX3600, I suspect it would be quite some time before we see a usable port. The firmware is currently based on Qualcomm’s QSDK instead of the main OpenWRT tree, which means there might be proprietary changes and drivers that are not available in the main tree (yet). Unfortunately, this is also something I don’t have time to work on, or assist with. The stop-gap solution I have come up with is firmware modding.
Knowing how the update file is structured, we can extract the firmware, remove the protections, and flash the patched firmware directly.
The update image primarily contains a “root.ubi” portion that is a UBI volume, which has both the kernel and root filesystem in it. Fortunately, the RSA signature on the update image is only verified at the time a new firmware is uploaded and flashed, and not part of a secure boot chain like Android or iOS devices. The kernel portion uses a U-Boot FIT uImage format, which combines the kernel, device-tree blobs and some hashes and settings in a device-tree-like format. The root filesystem is just a squashfs, so it can be unpacked and repacked easily with existing tools.
I wrote a tool called xqrepack, which basically takes the official firmware, dissects it, performs some modifications and puts it back together. The important goal of this modding process is to preserve SSH and UART access, as the official firmware disables them after every upgrade. SSH is crucial to allow direct access to OpenWRT (or Linux) so that we can set up the wireless and Gigabit networking exactly how we want it.
The other task is to remove phone-home functionality from the firmware. In my review, I have mentioned the web UI tracking that is evident by looking at your browser network requests. In the firmware image, I have noticed more logging & collection of statistics on the router, which is routinely uploaded to Xiaomi. If there are any crashes or failed upgrades, these are also reported back to Xiaomi (along with your WiFi configuration settings), which I assume helps them be aware of and fix these problems. Last but not least, using the AIoT functionality of the router also requires interaction with the Xiaomi servers. This has been the case for all of their IoT products anyway. xqrepack will remove all the AIoT functionality and other phone-home mechanisms. Note that in doing so, you will lose AIoT functionality, and also the WAN LED indicator because it pings their servers as a connectivity test. If this is something that you cannot accept, then you should not use this tool, or you can modify the tool yourself.
There has been a few reports of the tool working successfully with the latest version, 1.0.67 at this time of writing, including myself. If you encounter any problems, please feel free to file issues (or pull requests) on the GitHub project.
Once you have a modified firmware image, you can flash this onto your router, using the SSH access obtained in the previous section.
Now, you have a wireless router with updated drivers and firmware, which you can customize beyond what Xiaomi has allowed.
Advanced Wireless Features
For my networking requirements, I need a VLAN segregated guest network, and I also use WPA Enterprise on my network.
Digging into the firmware, Xiaomi has relied on QSDK from Qualcomm to base their firmware on. Internally, it uses
hostapd for creating the wireless APs, which means it is quite flexible, and is invokved in such a way that respects the OpenWRT UCI config. Because this firmware uses a dumbed down web UI, we will have to directly edit the OpenWRT config files to achieve what we need.
The wireless AP settings are stored in
/etc/config/wireless. An existing AP entry looks like this:
config wifi-iface option device 'wifi0' option ifname 'wl0' ... option encryption 'psk2+ccmp' option sae '1' option sae_password 'mywifipassword' option key 'mywifipassword' option ieee80211w '1' option ssid 'Xiaomi_1234`
The important parameter here is
encryption. You can find the full list of “WPA Modes” in the OpenWRT guide here. Anything that is
sae uses a pre-shared key.
In order to use WPA Enterprise, the “encryption” setting needs to be
wpa*. If you have only modern devices and don’t have legacy devices trying to connect, you can go ahead and use
wpa3-mixed for WPA2/3 Enterprise mode. Otherwise, a good option might be
You will also need to specify the RADIUS server settings with
auth_secret. You don’t need to specify the
auth_port unless it’s not 1812. Verify that the hostapd file generated at
/var/run/hostapd-wl*.conf is correct.
A modified section should look like this:
config wifi-iface ... option encryption 'wpa2+ccmp' option ssid 'Xiaomi_1234' option auth_server '192.168.0.1' option auth_secret 'testing123'
VLAN Segregated Guest Network
I typically have a guest SSID set up; this is easy to do on a more “advanced” router. In addition, I also want traffic to/from this guest AP to be separated out into its own VLAN.
You will need to create the guest APs (or wireless interfaces) by copying and pasting the current sections from
There are 3
wifi1 correspond to the 5GHz and 2.4GHz radios for the router, and
wifi2 (as I speculated in the review) is the 2.4GHz radio for AIoT.
config wifi-device 'wifi0' option type 'qcawificfg80211' option macaddr '88:c3:97:aa:bb:cc' option hwmode '11axa' ...
Depending on which radio you want your AP to be on, use the appropriate
After the initial router setup, there should have been 2
wifi-ifaces created by default, one for each band or
config wifi-iface option device 'wifi0' option ifname 'wl0' option network 'lan' option mode 'ap' option wpsdevicename 'XiaoMiRouter' option ssid 'Xiaomi_1234' ...
You will need to duplicate the
wl1 interfaces to create your own virtual APs. Note that the interface names cannot have dots, so I have named them
wl11 (a 1 suffix). You can set a different PSK for the virtual APs here or have them use different authentication mechanisms, like WPA Enterprise which I have mentioned.
To put them on a separate guest network, create a “guest” bridge by adding an entry in
/etc/config/network. There should already be a “lan” interface section, which is where the LAN ports
eth4 are currently placed.
This section creates a bridge called
br-guest and places VLAN 10 of all LAN ports into it:
config interface 'guest' option proto 'static' option ifname 'eth2.10 eth3.10 eth4.10' option type 'bridge'
The interfaces listed in
option ifname will be created automatically. Make sure the
wifi-iface section also specifies
option network 'guest' in order for the guest APs to be placed in the same VLAN 10 network.
After you have updated the settings, you can use the
wifi reload command to re-configure the network devices, or you can just reboot. To verify that the correct settings have been applied, use
root@XiaoQiang:~# brctl show bridge name bridge id STP enabled interfaces br-guest 7fff.88c300aabbcc no eth2.10 eth3.10 eth4.10 wl01 wl11 br-lan 7fff.88c300aabbcc no eth2 eth3 eth4 wl0 wl1
Now, wireless clients that join those APs will be placed on this “guest” network on a separate VLAN. Wireless clients that join the main
wl1 network will go out over the LAN ports as normal, untagged.
One odd thing I noticed with this setup is that DHCP, DNS and ping requests can get through, but HTTP downloads do not work. Running
tcpdump on both the server and the wireless router, I noticed that larger packets of the HTTP traffic did not make it through to the router. The main network did not exhibit this problem though.
I soon realized the problem was related to MTU size. While debugging the VLAN config, this
swconfig output caught my eye:
root@XiaoQiang:~# swconfig dev switch0 show Global attributes: enable_vlan: 1 max_frame_size: 1518 dump_arl: MAC: 00:0d:bb:aa:bb:cc PORTMAP: 0x08 VID: 0x9 STATUS: 0x0 ...
The maximum frame size accepted by the switch was 1518, a typical 1500 MTU size plus Ethernet overhead. However, note that encapsulating traffic in a 802.1Q VLAN would add a 4-byte tag, causing the length to increase beyond the size of a typical Ethernet frame.
One easy way to fix this was to set the MTU on the server's interface lower. The default MTU is 1500, so we need to reduce this by 4 to accomodate the VLAN tag:
ip link set dev eth0 mtu 1496
After this, all traffic could pass through the guest network properly, thereby confirming this hypothesis. This would be a hassle if there were multiple devices plugged in to the router that needed to communicate with wireless guests.
I tried doing the reverse, to make the router accomodate larger MTUs:
root@XiaoQiang:~# swconfig dev switch0 get max_frame_size 1518 root@XiaoQiang:~# swconfig dev switch0 set max_frame_size 1528 failed
I noticed that the system scripts also used
ssdk_sh to set parameters for the switch, so let’s try that:
dev0@qca>misc frameMaxSize get This request is not support dev0@qca>misc frameMaxSize set 1528 This request is not support
I am afraid the frame size is either hardcoded in the drivers somewhere, or worse, in the hardware. This also means that jumbo frames are not supported.
Some routers allow you to turn off the LEDs to be more disceet, or to not be disturbed at night. The AX3600 indicator lights are quite tame, compared to other devices, but in a dark room it can still be distracting. You may also want to re-purpose the indicator lights for your own use.
The good news is that all the LEDs are available in sysfs:
led_yellowfor the SYSTEM indicator
net_yellowfor the INTERNET indicator
led_anton the AIoT antenna indicator
I wrote a toy script to sequence the LEDs, just for fun.
As I mentioned in the review, this is really good router hardware for the price (US$100). You get a 802.11ax router with 4×4 MIMO configuration, 2×2 MIMO for the 2.4GHz band, and an extra 2.4GHz radio for AIoT which you can re-purpose, all powered by a 64-bit quad-core ARM CPU. And now that I realized that you can easily customize the network settings without jumping through too many hoops, it’s an even better value (for me, at least).
You can find the xqrepack tool to repack the firmware on GitHub here, together with some instructions on how to use it. You can also check out the OpenWRT documentation for more resources on how to configure the OS in general — it was a great help to me.
I will still need to assess the long-term stability of the router though, to see if the drivers lock up over time, or stop accepting clients, or stop routing traffic, etc.