Unbricking a TP-Link TL-WA801ND v2


Experimenting with embedded devices is fun but things not always work as expected. Sometimes you just flash the wrong firmware. So did I. After having done so I furthermore realized that the bootloader in my TL-WA801ND v2.1 was the current one and therefore contains a bug (or maybe it was deliberately crippled?). The impact of this bug was that you’re not able to load something via TFTP from the bootloader. How to unbrick this device? Is it possible at all? To anticipate the answer: It is. But at intermediate level…

Before I go into the details a hint about the commands I use to create files and stuff like that. I mainly work with a Windows machine but regularly use a *nix like environment on that machine. For this purpose I’ve installed Cygwin which provides me a lot of non-Windows tools I’m regularly using.

The very first step was to identify the flash chip itself. In the picture below I marked the flash on the PCB. It is located next to the UART header JP1 (unpopulated in this picture). It is a S25FL032A/P from Spansion.

TL-WA801ND Flash PositionUnfortunately it can’t be flashed while soldered. To flash it from outside of the device it needs to be desoldered. Attention: desoldering a SOP-8 chip requires good soldering skills. If you have a soldering tweezers it is a bit easier. In any case you might cause a severe damage on the device. Do it at your own risk.

Preparing the firmware

Before I flashed a new firmware into the desoldered flash had to prepare a file containing a good one. The flash is logically divided into five parts which are as follows:

00000000:0001ffff uboot
00020000:0011ffff kernel
00120000:003dffff rootfs
003e0000:003effff config
003f0000:003fffff art

The “uboot” contains the bootloader which loads the real firmware consisting of “kernel”, “rootfs” and “config”. The last block is the so-called Atheros Radio Test (ART) and contains vital data for the radio chip. As this is the only one I would like to have from the old flash I started by extracting this one. In order to get it I first extracted the complete flash content:

flashrom -p buspirate_spi:dev=COM7,spispeed=2M -r bricked.bin
As you can see I used a Bus Pirate to which I connected a SOIC clip (Pomona Model 5250). The Bus Pirate was connected to the flash chip according to the following diagram:
Connecting Bus Pirate to SPI FlashThe ART partition then was retrieved with
dd if=bricked.bin of=art.bin bs=1 skip=4128768
The next ingredient will be the bootloader. As the old bootloader was crap I wanted another one from a former version. The malfunctioning bootloader is distributed by TP-Link along with the latest firmware update available from their website or even preloaded with newer devices. Unfortunately the former version is not provided with the firmware version before. But I was in luck to have another TL-WA801ND which still has the working bootloader. So
dd if=/dev/mtd0 of=/tmp/u-boot.bin
on the access point did the trick (if you don’t have an access point with a good bootloader I placed a file in my dropbox). I grabbed the resulting file from the access point and placed it in the same folder as the art file. As I grabbed the bootloader from another access point it can’t be used right away as the bootloader also contains the MAC address to be used for it. To display it the command
hexdump -n 6 -s 130048 -e '"%06.6_ax " 5/1 "%02X:" 1/1 "%02X""\n"' u-boot.bin
will do. To change it (the MAC address of the device can be found on the sticker at the bottom of the case) I issued
newmac=12:34:56:78:9A:BC
echo $newmac | gawk -b -F ':' '{ for (i=1; i <=NF; i++) { printf("%c", strtonum("0x"$i)); } }' | dd conv=notrunc bs=1 count=6 seek=130048 of=u-boot.bin
Note that the above MAC is not a real one.
Right before the art partition I wanted to have a cleared config area. This area is 64 Kbyte long and in order to have it cleared it needs to be filled with 0xFF. Creating such file can be done with
dd if=/dev/zero bs=1 count=65535 | tr "00" "\377" >ffed64.bin

The last part will be the firmware. I decided to use the stock one from TP-Link but not the latest one so I didn’t have to remove the bootloader from it. At the end I had the 4 files

  1. u-boot.bin
  2. wa801nv2_en_3_13_20_up(120524).bin
  3. ffed64.bin
  4. art.bin

Those were concatenated by

copy /b u-boot.bin+wa801nv2_en_3_13_20_up(120524).bin+ffed64.bin+art.bin recover.bin
getting a new file “recover.bin” which needed to be flashed.

Flashing

To flash the firmware with flashrom an appropriate layout file is required. The above layout is exactly in the format needed so I simply put it in a file called “rom.layout”. Finally

flashrom -p buspirate_spi:dev=COM7,spispeed=2M -n -w recover.bin -l rom.layout -i uboot -i kernel -i rootfs -i config -i art
writes the created firmware into the flash. The very last step was then to solder the flash again and power on the device. Bang! The TL-WA801ND booted with stock firmware again. Of course I updated it with OpenWRT afterwards.
Advertisements

36 thoughts on “Unbricking a TP-Link TL-WA801ND v2”

  1. It’s probably a stupid questions given your detailed description, but just to be clear. I cannot flash the TL-WA801ND v2.1 without removing the chip? -_-

      1. Hallo…

        Flashing the device without desoldering of the FLASH is possible. All you need is a running bootloader with possible mm command and connecting the uart to device.

        I wrote a little script below, to flash a new kernelimage to the device without TFTP Client. Only Uart Bootloader Console is needed and my python script.

        I posted my code, but all tabs and spaces where deleted. So this code is quite buggy.

        If you are interested in my code, send me an e-mail adress or a public storage to upload the script.

        Good Luck
        Regards Christian

  2. Hi,
    Can this procedure be used for unbricking the TL-WA801ND V1.1 ? If so, can the 2.1 bootloader you have uploaded to dropbox be used for TL-WA801ND V1.1 ?

    thanks

  3. Hello, i have a problem with my repeater.
    i haven’t modified anything (it’s virgin xD ), but i have the problem of the power led everytime on, and the other 4 leds blinking together (it’s seems bricked).
    I used it for a long time (like 7 moth without power off (just once every 2 weeks for a couple of minutes), then I haven’t used anymore because I moved.
    Now without reason it’s bricked.
    I Tryed to connect a serial port to USB made by prolific (NOT TTL) and putty doesn’t show anything….
    what can i do? i don’t want to spend money for a programmer that cost like the repeater.
    Thank You.

  4. Hello together……

    At first sorry for my bad english.

    I have found and checked a way to unbrick a TP-Link Device with a cripped Bootloader (Bootloader without working TFTP Client) without desoldering and external flashing.

    At first, the problem is how to get the new Firmware in RAM without TFTP transfert. After some time reingeneering the cripped u-boot i found a way to manipulate the RAM content very easy with only some possibilities of commands.

    The way is to use the mm command (memory manipulating command of u-boot). Ok… thats fine, but how can i automate the input of all 4Byte blocks in the boot loader console?

    The answers was writing a little programm with this functions …
    1. Reading the *.bin file in an array
    2. Ordering all bytes in blocks of 4Bytes (same order als mm command need)
    3. Automating the Bootloader stop command with “tpl”
    4. Automate the first command “mm 0x81000000”
    5. Read the answer of device with Adress and Content like “0x81000000 : 0xffffffff ? ”
    6 Bilding a loop to send all the 4 Byte blocks to Device with new Content Answers.
    7. and so on for the hole *.bin file.
    8. After that change the automating console to human console input
    9. Sending erase 0x9f020000 +0x3c0000 (eeprom erase)
    10. Sending copy command cp.b 0x81000000 0x9f020000 0x3c0000 (copy ram->flash)
    11. after “done….” sending bootm 0x9f020000 (booting kernel from flash)
    12 ….. ***Bang*** Thats the goal.

    I´m felt glad to found a way unbricking the device without any money or desoldering.

    If someone is interested in getting the source code…. no problem. I will post the code. But the code is not released or best praxis at the moment. It is a little python script, looks like a “Quick Hack”, and written in 20 minutes. So at is at it is.

    In the next days or weeks i will spend some time to optimate the code.

    Thank You ….
    Regards Christian

  5. Hello twice ….

    Here is my code. For your information: Sending OpenWRT Image to device needs 02:12:00 houres…. Is long but better als desoldering…

    #
    # Some Inports
    #
    import sys
    import string
    import serial

    #
    # Init Vars
    #
    offset = 0x81000000; # Start Adress in RAM

    #
    # function for missing printf
    #
    def printf(format, *args):
    sys.stdout.write(format % args)

    #
    # Reading bin file, converting to hex, ordering to 4 Byte Blocks
    #
    binarray=[0 for i in range(1016012)]; # Init Array
    str = open(“openwrt.bin”,”rb”).read() # Define Filename in
    hexStr=””
    count = 0; # Init 4 Byte Block Counter
    for x in range(0, len(str), 4): # Loop on str var with step 4
    hexstr=””; # Init 4 Byte Block Content
    hexStr=hex(ord(str[x]))[2:]; # converting bin to hex
    if len(hexStr) < 2: # checking on 1 collum only
    hexstr=hexstr + "0" + (hexStr).strip(); # insert pre 0 if needed + first byte of block
    else:
    hexstr=hexstr + (hexStr).strip(); # first byte of block
    if x+4 <= len(str): # are there some bytes missing?
    for y in range(1, 4): # yes, fill in the missing bytes of block
    hexStr=hex(ord(str[x+y]))[2:]; # converting missing bytes to hex
    if len(hexStr) 0: # are the some bytes missing after last block?
    for z in range(0, Rest): # loop on missing bytes after last block
    #
    print x+z; # debug output
    #
    hexStr=hex(ord(str[x+z]))[2:]; # convert bin to hex
    if len(hexStr) < 2: # checking on 1 collum only
    hexstr=hexstr + "0" + (hexStr).strip(); # insert pre 0 if needed
    else:
    hexstr=hexstr + (hexStr).strip(); # insert one missing byte

    for w in range(Rest, 4): # fill in all missing bytes of block without content
    hexstr=hexstr + "00";

    # print "Adress:", hex(offset+x), "Arraycount:", count, "Byteblock:", hex(x), "Block:", hexstr; # Debug
    binarray[count]=hexstr; # copy converted content to Array

    # print binarray[int(0xb5ac)/4]; # Offset-Debug output

    #
    # Serial Console emulation with little output parser
    #
    port = serial.Serial("/dev/ttyUSB0", 115200, timeout = None); # define Serial
    port.flushOutput(); # clear output buffer
    port.flushInput(); # clear input buffer

    # Read line on serial up to CR is incommung
    def serialrdln(pruefung): # funktion on parsing input
    while True:
    zeile = port.readline().strip(); # reading one line on serial up to CR
    log(zeile, "in"); # Log output
    if (pruefung) != "": # check if input is empty
    if zeile == (pruefung): # check if input = parsing line
    return zeile # return with arg

    # Reading Serial byte by byte and checking on incomming word
    def serialrd(word): # function on parsing word
    wordlen = len(word); # lenght of parsing word
    count = 0; # collum conter = 0

    # log("Waiting for: " + word, "log"); # Debug Output

    while count ” + data;
    if typ == “out”:
    print ” “);
    log (“State1: Sende mm mit Offset”, “log”);
    serialwriteecho(“mm ” + (hex(offset)) + “\r\n”);
    line = serialrd_input(22);
    print line;
    state = 2;

    if state == 2:
    for t in range (0, count+1):
    serialwriteecho(binarray[t] + “\r\n”);
    line = serialrd_input(22);
    print line;

    port.close();
    break

  6. Hallo …..

    With my post i will send a better source code of my python script for flashing a TP-Link AP with crippled or buggy bootloader 1.1.4.

    Before using the script connect the uart with Converter to 3,3V to the device. Start the script and then switch on the AP.

    Good Luck
    Regards Christian

    ——————————————————————————————-

    #!/usr/bin/python

    #
    # Some Inports
    #
    import sys # Import for sys.stdout.write
    import string # Import for string handling
    import serial # Import for Serial communication

    #
    # Init Vars
    #
    imagefile = “openwrt.bin”; # define new imagefile
    debugmode = “true”; # set Debugmode to true or false if needed
    stopboot = “tpl”; # word for stopping bootloader on TP-Link
    offset = 0x81000000; # Start Adress in RAM
    offsetflash = 0x9f020000; # start Adress of kernel image in flash
    imagelenght = 0x3c0000; # lenth of openwrt image

    #
    # function for missing printf
    #
    def printf(format, *args):
    sys.stdout.write(format % args)

    #
    # Reading bin file, converting to hex, ordering to 4 Byte Blocks
    #
    str = open(imagefile,”rb”).read(); # Define Filename in
    binarray=[0 for i in range((len(str)/4)+1)]; # Calculating the width of Binarray
    hexStr=””; # Init Var
    count=0; # Init 4 Byte Block Counter
    for x in range(0, len(str), 4): # Loop on str var with step 4
    hexstr=””; # Init 4 Byte Block Content
    hexStr=hex(ord(str[x]))[2:]; # converting bin to hex
    if len(hexStr) < 2: # checking on 1 collum only
    hexstr=hexstr + "0" + (hexStr).strip(); # insert pre 0 if needed + first byte of block
    else:
    hexstr=hexstr + (hexStr).strip(); # first byte of block
    if x+4 <= len(str): # are there some bytes missing?
    for y in range(1, 4): # yes, fill in the missing bytes of block
    hexStr=hex(ord(str[x+y]))[2:]; # converting missing bytes to hex
    if len(hexStr) 0: # are the some bytes missing after last block?
    for z in range(0, missing): # loop on missing bytes after last block
    if debugmode==”true”: print “Adress:”, hex(x+z); # debug output
    hexStr=hex(ord(str[x+z]))[2:]; # convert bin to hex
    if len(hexStr) < 2: # checking on 1 collum only
    hexstr=hexstr + "0" + (hexStr).strip(); # insert pre 0 if needed
    else:
    hexstr=hexstr + (hexStr).strip(); # insert one missing byte

    # After working on last missing Bytes, fill up the last empty Bytes of Block with FF
    for w in range(missing, 4): # fill in all missing bytes of block without content
    hexstr=hexstr + "FF"; # filling up with FF
    if debugmode=="true": print "Fill up next empty Byte of Block with FF";
    if debugmode=="true": print "Offset:", hex(offset+x), "Arraycount:", count, "Byteblock:", hex(x), "Block:", hexstr; # Debug
    binarray[count]=hexstr; # copy converted content to Array
    count +=1; # array block counter +1

    #
    # Serial Console emulation with little output parser
    #
    port = serial.Serial("/dev/ttyUSB0", 115200, timeout = None); # define Serial
    port.flushOutput(); # clear output buffer
    port.flushInput(); # clear input buffer

    # Read line on serial up to CR is incommung
    def serialrdln(pruefung): # funktion on parsing input
    while True:
    line = port.readline().strip(); # reading one line on serial up to CR
    log(line, "in"); # Log output
    if (pruefung) != "": # check if input is empty
    if line == (pruefung): # check if input = parsing line
    return line # return with arg

    # Reading Serial byte by byte and find a defined word
    def serialrd(word): # function on parsing word
    wordlen = len(word); # lenght of parsing word
    charcount = 0; # character conter = 0
    while charcount “, data;
    if typ == “out”:
    print ” “); # parsing console prompt
    log (“State1: Sending mm with offset”, “log”); # log sending mm command with right offset Adress in RAM
    serialwriteecho(“mm ” + (hex(offset)) + “\r\n”); # sending mm command with right offset Adress in RAM and CR with echo
    line = serialrd_input(22); # reading answer from device with offset adress and content
    printf (line); # printing output from device to console
    state = 2; # change to state 2

    if state == 2: # automating the content input to device
    for t in range (0, count): # loop for count of blocks
    serialwriteecho(binarray[t] + “\r\n”); # sending content to port with CR
    line = serialrd_input(22); # reading answer from device with offset adress and content
    printf (line); # printing output from device to console
    state = 3; # change to state 3

    if state == 3: # image is send to ram, stopping mm console with quit
    serialwriteecho(“quit\r\n”); # sending q with CR to port with echo return from device
    data = serialrd(“wasp> “); # parsing console prompt
    state = 4; # change to state 4

    if state == 4: # console input, erasing FLASH
    serialwriteecho(“erase ” + (hex(offsetflash)) + ” +” + (hex(imagelenght)) + “\r\n”); # send erase Flash
    data = serialrd(“wasp> “); # parsing console prompt after earasing
    state = 5; # change to state 5

    if state == 5: # erasing FLASH is done, copy RAM to FLASH
    serialwriteecho(“cp.b ” + (hex(offset)) + ” ” + (hex(offsetflash)) + ” ” + (hex(imagelenght)) + “\r\n”); # send copy to FLASH
    data = serialrd(“wasp> “); # parsing console prompt after flashing
    state = 6; # change to state 6

    if state == 6: # flashing is done, boot from flash
    serialwrite(“bootm ” + (hex(offsetflash)) + “\r\n”); # send boot from flash to device
    port.close(); # close port to device

    break

  7. regards Christian

    Please verify scripts when reading the file openwrt.bin is taking a more character “L” in the String part

    Offset: 0x81000000L Arraycount: 0 Byteblock: 0x0 Block: 01000000

    The size of the * .bin is 0x81000000

    I think the right thing to be without the “L”

    Offset: 0x81000000 Arraycount: 0 Byteblock: 0x0 Block: 01000000

    when this ending run this command

    erase 0x9f020000L + 0x3c0000
    cp.b 0x81000000L 0x9f020000L 0x3c0000
    bootm 0x9f020000L

    right when I think should be without the “L”

    erase 0x9f020000 + 0x3c0000
    cp.b 0x81000000 0x9f020000 0x3c0000
    bootm 0x9f020000

    1. Hi Bonsai,

      yes, that is the normal way but we are talking about a way to unbrick the device with deactivated tftp connection on bootloader. Congratulation, you have a bootloader with full function. So…. never update/reverse the device with the latest tp-link firmware. After that you have the same buggy bootloader in your device….

      On that you can use my script from here: https://tasksofohm.wordpress.com/hardware/bringing-openwrt-to-tl-wa801nd-part-2-building-openwrt/

      Regards Christian

  8. Hello Christian,

    i have a wa801nd and a problem i hope you might be kind enough to help me with.. if possible.

    the problem in brief is that i’m unable to connect to the unit through LAN, once i plug the cable, the LAN led turns off, and when i unplug the cable, LAN turns back on again. if i’m not mistaken, this should be the other way around!!

    when the original firmware by tp-link was still on the unit, i could connect to it wirelessly but not through LAN. so i figured, why not flash your openwrt rom and try it out. i was mistaken. now the AP boots up without wireless (standard openwrt first boot), and i’m unable to connect at all, not through wlreless, nor LAN.

    from what i observed, the unit “is” working fine, all except for the “LAN” part. but i can’t connect unfortunately.

    what do you suggest?

    thank you

  9. Hi mjay,

    there is still a way to connect the device through UART (RS232). But think about the different Voltage Level between the device Port and the PC UART. Don´t connect the PC to the device without the right Level Shifter.

    For standard PC Rs232 Port the following connection is needed.

    The other way is to connect the device via usb to TTL like DKU-5 data cable.

    Next step is to open a standard console on RS232 and connect/Login to the openwrt sytem. On this session you can configure your wifi as you want, or use

    Could you please explain me more details with your problem on your LAN Port? I need more information……

    regards

    Christian

    1. Hello Christian

      Apologies for the late reply.

      The problem with the lan port is weird. Let’s say I boot up the AP without plugging the cable. It boots just fine (from what I can see from the leds), then all of a sudden the lan port led turns on (without the cable). After that if I plug the cable, the lan led would turn off. On the other end the PC starts trying to connect, but eventually gives me a message saying the network cable is unplugged. At this point if I unplug the cable the lan led (which is off) turns back on.

      In simple words it’s acting exactly the opposite to the way it should with regard to the lan led responding to plugging and unplugging the ethernet cable.

      When plugged, if I try to ping/ssh/telnet the AP, I get a “host not found” error..

      That’s about it I guess.

      Now, if I go with the USB to TTL cable option, do I still need a voltage level shifter?

      Thanks

    1. Hi mjay,

      there are never to many questions.

      So let me first give you some answers…. You are right. Your adapter is the right way to connect to your device without any other level shifter (It is included for 3.3V and 5V).

      But i think it is not the best way to configure the flashed firmware over uart because it seems verry buggy. So on my oppinion the best way is to flash a new firmway with all you working functions are included.

      Could you please test flashing the firmware with tftp on bootloader…?

      After that all your needed configurations are working as default.

      Regards
      Christian

  10. Hi there,

    I have an WR1043ND v2 router and after attempting to flash the original firmware (I was having some performance issues and thought OpenWRT was the cause) my device is in a boot loop. I should have flashed the tplink firmware without the bootloader probably. I’ve soldered pins for the serial connection and used my Aten USB serial converter to connect to the router(only Tx,Rx and GND). Putty and the Com port settings are ok (115200, 8N1, No flow ctrl) but strange characters are appearing in the console and it won’t accept any commands. Now I’m not sure why is this happenning. Can the above script be used for my router too? How can I run the php script?

    Thanks,
    Nico

    1. Hi Nico,

      your experimental things are the best way to kill your device.

      Please disconnect your device from your PC as soonest as is can. Your USB to Uart converter is not the right thing because the output is not TTL or 3.3V. It is +/- 12 Volt so you can’t connect to your device, only kill the uart front end of your device.

      Please use the right adapter and read all the post to this on this Page at first.

      Regards
      Christian

  11. Like most TP-Link access-points/routers it will try to download a recovery image over tftp if bricked. Just start a tftp server at 192.168.0.66, and put an image (eg. the original firmware) in the root and name it wa801nv2_tp_recovery.bin (you can verify by using tcpdump or wireshark). Start the access point and press the reset button for a couple of seconds. No soldering required.

  12. Hey Guys,

    I have a TL-WA801ND that is stuck in a boot loop, I can get to the “wasp>” prompt however tftp does not work – I assumed this has to do with the Ethernet port not being able via uboot….

    My question is how do I use your phyton script to manually upload the openwrt software? Can this be done in windows?

    It was bricked with dd-wrt firmware; I was trying to revert to stock firmware….

      1. Thank you Christian,

        I got through with the script…..one thing though, I had to time the auto-boot on the TL-WA801ND because it would get stuck after sometime; So I started the script and when it got close to the end of the firmware conversion, I powered up the TL-WA801ND.

  13. where i typ all this commands?
    i got win, and i cant get any ip address from my reapiter
    he just turn on and off, my switch get connection and lost every 5 sec

    what i can do?

  14. someone can explain me what can i do to unbrick wa801 v2.1 whitout desoldering the chip?

    i want upload original firmware……

    thanks

  15. i’ve tried to use python script changing ttyUSB0 to Com8 (using usb to ttl device) but when i run the script i recive this error :

    File “tpf.py”, line 44
    hexstr=hexstr + “0” + (hexStr).strip(); # insert pre 0 if needed
    ^
    IndentationError: expected an indented block

  16. i’ve debugged the script it’s all error relative at tabs spacement and parethesis during print command, now the script start but give this error:

    File “C:\Users\admin4\Desktop\tpflash.py”, line 30, in
    binarray=[0 for i in range((len(str)/4)+1)]; # Calculating the width of Binarray
    TypeError: ‘float’ object cannot be interpreted as an integer
    how can i fix it?

    thanks.

  17. Hey Marco,

    Can I suggest you use a Linux OS (you can use a live cd) to run the script – its a bit easier and less buggy that way….

    1. Using linux everythings Goes ok :)
      I’ve Just debricked The device!
      On Linux python workshop bettee than Windows :) At first script run And I’ve uploaded open wrt Image. ..
      So i decide To Revere Back To originale firmware, with winspc And ssh commando :) thanks To all!

  18. You can get instructions for programming with SPI programmer?
    I accidentally deleted all ( with usb to ttl adapter, with putty, command “ERASE ALL” )
    Thanks

  19. Don’t know if this is the right place to ask. But can I get the wa801nd-v2 to fetch firmware from tftp without bricking it first? Is there any combination of power on or reset that trigger a tftp boot fetch procedure?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s