Installing OpenWRT on a TP-Link TD-W8970

4 June 2020

Flashing is a risky procedure that can break your devices. Follow anything I mention here at your own risk.

I recently retired this router from active service, so I thought it would be interesting to try OpenWRT on it. If it works, I can put it aside as a spare. If it dies, no matter.

But first... the TD-W9980

The 9980 contains the same chipset as the 8970, so it is possible to flash its firmware onto the 8970. Doing so will give you access to the VDSL capabilities of the modem, and the wireless guest mode. The final 9980 firmware is also slightly newer than the final 8970 firmware.

It's really easy to do, and has about the same risk as an ordinary update. It won't accept the 9980 firmware as is - you have to edit the header to say it belongs to the 8970. Instructions are around on the Internet so I won't detail them here, but it's a good option if all you want is access to the VDSL modem.

Root Shell Access

The 8970 supports telnet access out of the box. Login and... oh. Instead of a bash shell or similar, it's some sort of Cisco IOS-esque management interface. You can query and configure some aspects of the router, but for logging it's actually easier to scrape the web interface with curl. Anyways, this is not what I want.

There is a reasonably simple way to get to the real shell. Download the configuration file using the backup option in the web interface. You might find it's obfuscated, depending on what version of the firmware you're running. Mine was, but luckily the program tpconf_bin_xml can decrypt and encrypt these configuration files. After decryption, edit it and insert (or modify) the following XML within the <DeviceInfo> tags:

<Description val="TD-W8970 v1`telnetd -p 1023 -l login`" />

This will cause a telnet daemon to be executed on boot. So encrypt the XML, restore it, and reboot. Afterwards you should be able to telnet onto port 1023 (admin/1234) and gain access to a real root shell.

Screenshot showing the telnet command as the router's model name.

This visual oddity will also appear in the web interface. (9980)

Backup, Backup, Backup

I wanted a backup image of the firmware, especially the partition that contains the unique data for the wireless chip. nanddump was the tool to use, as it's tailored for use with flash memory. It's included in most busybox binaries, but not the one inside the stock firmware.

I downloaded an unofficial binary of the MIPS version of busybox, and although some of the applets worked, nanddump wouldn't. Attempting to run broken applets caused the terminal to freeze, at least until Control-C was pressed. dmesg reported:

FPU emulator disabled, make sure your toolchain was compiled with software floating point support (soft-float)

So I needed a binary with software FPU emulation (remember when x86 CPUs didn't have the x87 built-in?) Lazy me couldn't find any other suitable pre-compiled binaries, so I used buildroot to make one.

With that, dumping the flash was a simple case of running 7 variants of the same command:

# ./nanddump -f /var/usbdisk/sda1/mtd0.bin /dev/mtd0 ECC failed: 0 ECC corrected: 0 Number of bad blocks: 0 Number of bbt blocks: 0 Block size 65536, page size 1, OOB size 0 Dumping data starting at 0x00000000 and ending at 0x00020000...

and again for mtd1 to mtd6.

No Error Correction?

OOB size 0? The flash memory used in the router is an EN25Q64, which holds exactly 8,388,608 bytes. The total size of all dumped partitions is also 8,388,608 bytes. A bad block table isn't stored within those, and the datasheet doesn't say anything about error handling. Therefore I have to assume that there is no bad block handling in this device. A worn out memory block is probably fatal.


I had to decide which OpenWRT version to use. Most of the success stories came from those who flashed 15.05. The latest version contains many improvements for this chipset, but it's a bigger file which requires more writes to complete. More writes = higher risk. I decided the risk was still reasonable enough to use the latest version (as of now), 19.07.3.

The OpenWRT firmware image needs to be split to accommodate the two main partitions, mtd1 and mtd2. Piece one, for mtd1, has to be exactly 1,310,720 bytes. Piece two is the rest of it, up to a maximum of 6,684,672 bytes. Any hex editor will do.

So with the two halves of the OpenWRT image and nandwrite ready on the USB disk, it's almost time to flash. I closed some processes first, in an attempt to prevent them from trying to access the flash while I'm writing to it.

# killall -1 upnpd # killall ushare cwmp noipdns dyndns Warning Reminder:
Be very careful from the moment you issue the first erase command. With the filesystem gone, any command that attempts to access it will hang and you will be locked out! Make sure all the files you need are together, and type every command carefully.

Bravery time. flash_erase (part of mtd-tools) erases the partitions containing the stock firmware:

# ./flash_erase /dev/mtd1 0 0 Erasing 64 Kibyte @ 130000 -- 100 % complete
# ./flash_erase /dev/mtd2 0 0 Erasing 64 Kibyte @ 650000 -- 100 % complete

Now nandwrite can program in OpenWRT:

# ./nandwrite -p /dev/mtd1 /var/usbdisk/sda1/piece1.bin Writing data to block 0 at offset 0x0 ... Writing data to block 19 at offset 0x130000
# ./nandwrite -p /dev/mtd2 /var/usbdisk/sda1/piece2.bin Writing data to block 0 at offset 0x0 ... Writing data to block 63 at offset 0x3f0000

To confirm that the data was written correctly, I immediately dumped the two partitions and compared them with the files I programmed. They matched (with padding). The flash appeared to be successful.

Moment of truth! I turned the power off, then on again.

It took a minute to boot, but it did. OpenWRT seems to use the WPS LED to show booting status, which is different to the stock firmware. Once it'd finished, I was able to load the web interface.


It wasn't as hard as I thought to install OpenWRT. There is a lot of conflicting information on the Internet about the installation procedure, especially whether to use cat, dd, or nandwrite. I do think they are all viable, but I have used nandwrite successfully in this case.

Return to Blog Index








© Andrew Nile 2018-2024. Privacy