Imagine a scenario where you have a device running an embedded Linux system, but you flashed a bad firmware which doesn’t let you to have access to Ethernet/WiFi on this device. You only have access to it is using serial cable.
First thing you think is to use U-Boot transfer support over serial, but unfortunately you don’t have this option:
U-Boot 1.1.4 (Feb 27 2009 - 12:06:20) AP94 (ar7100) U-boot 0.0.12 (sic) In: serial Out: serial Err: serial Net: eth0, eth1 ### main_loop entered: bootdelay=1 ### main_loop: bootcmd="bootm 0xbf050000" Hit any key to stop autoboot: 0 ### main_loop: got key string, abort boot ### main_loop: no define CONFIG_AUTOBOOT_KEYED ### main_loop: CFG_HUSH_PARSER ### main_loop: parse_string_outer ## Booting image at bf050000 ... checksum:743d0796 Image Name: MIPS OpenWrt Linux-2.6.39.4 Image Type: MIPS Linux Kernel Image (lzma compressed) Data Size: 873389 Bytes = 852.9 kB Load Address: 80060000 Entry Point: 80060000 Verifying Checksum ... OK LZMA Umcompressing Kernel Image ... Image loaded from 80060000-802e82d8
As you can see it is not entering on U-Boot prompt because CONFIG_AUTOBOOT_KEYED is not defined.
Then we need to find another alternative.
Unfortunately we are not lucky, the linux system on this router doesn’t have “lrz” program installed.
But all is not lost, I have an idea!!!
The “lrz” program is relatively small, about 60KB, then I can convert it to text and past on Linux terminal running inside de box (using echo and pasting text). Unfortunately I cannot use base64 program, because it also is not install on this Linux system.
The remaining option is using hexdump (xxd) to convert the binary on text bytes and the recover it, as I suggested some times ago (link in Portuguese).
So, let to do it, first thing to do is download the package containing the lrz program (lrzsz_0.12.20-1_ar71xx.ipk).
Hmm, this is 59792 bytes long, no problem I hope.
Now let to convert it from binary to text:
$ xxd -g1 lrz > output.txt
We need to remove the “00xxxxx: ” from beginning of each line and the 16 chars representation at end of each line:
$ sed -i 's/^\(.\)\{9\}//g' output.txt $ sed -i 's/\(.\)\{16\}$//g' output.txt
Now let to convert this text back to binary to confirm it is working:
$ for i in $(cat output.txt) ; do printf "\x$i" ; done > mylrz
Let to check if they are have same binary sequence:
$ md5sum mylrz 08334803ce751a1f021a4de0c9c0e849 mylrz $ md5sum lrz 08334803ce751a1f021a4de0c9c0e849 lrz
Now just let to copy and past this content of text to linux box terminal.
I suggest you to use picocom instead minicom to do it:
$ picocom -b 115200 -l -r /dev/ttyUSB0
I started trying to send line by line this way:
root@OpenWrt:/# echo "7f 45 4c 46 01 02 01 00 01 00 00 00 00 00 00 00" >> mylrz.txt
In few seconds it became a very boring task and very prone to fail.
Then I decide to send commands directly to terminal over serial using shell script.
Leave picocom…
After some tests I noticed it is not possible to send many characters to terminal (over /dev/ttyUSB0), no more 2 bytes by time.
Then the command became this long line:
$ j=0; echo -n -e "ec" > /dev/ttyUSB0; echo -n -e "ho" > /dev/ttyUSB0; echo -n -e " \"" > /dev/ttyUSB0; for i in $(cat output.txt); do j=$(($j+1)); echo -n -e "$i" > /dev/ttyUSB0; echo -n -e " " > /dev/ttyUSB0; if [ $(expr $j % 16) -eq 0 ]; then echo -n -e "\" " > /dev/ttyUSB0; echo -n -e ">>" > /dev/ttyUSB0; echo -n -e "lr" > /dev/ttyUSB0; echo -n -e "z" > /dev/ttyUSB0; echo " " > /dev/ttyUSB0; echo -n -e "ec" > /dev/ttyUSB0; echo -n -e "ho" > /dev/ttyUSB0; echo -n -e " \"" > /dev/ttyUSB0; fi; done; echo -n -e "ec" > /dev/ttyUSB0; echo -n -e "ho" > /dev/ttyUSB0; echo "\"" > /dev/ttyUSB0
Verify if file lrz file was created:
root@OpenWrt:/# ls -l lrz -rw-r--r-- 1 root root 183113 Jan 1 01:19 lrz
Rename it to lrz.txt:
root@OpenWrt:/# mv lrz lrz.txt
Convert the text file to binary:
root@OpenWrt:/# for i in $(cat lrz.txt) ; do printf "\x$i" ; done > lrz root@OpenWrt:/# md5sum lrz 08334803ce751a1f021a4de0c9c0e849 lrz
Give it permission to execute and move to /usr/bin:
root@OpenWrt:/# chmod 555 lrz root@OpenWrt:/# mv lrz /usr/bin/
Execute the lrz command to receive file:
root@OpenWrt:/# lrz -Z
Leave picocom program (Ctrl+A+X)
In you computer execute this command to transfer firmware to your router:
$ sz --zmodem /tmp/openwrt-ar71xx-dir825.bin > /dev/ttyUSB0 < /dev/ttyUSB0
Check with md5sum to verify if it is correct:
root@OpenWrt:/tmp# md5sum openwrt-ar71xx-dir825.bin 90e938ed4a5aa825495c2b0b099655e7 openwrt-ar71xx-dir825.bin alan@aureo:~/Desktop/serial$ md5sum /tmp/openwrt-ar71xx-dir825.bin 90e938ed4a5aa825495c2b0b099655e7 /tmp/openwrt-ar71xx-dir825.bin
Now just update your system using this new firmware:
root@OpenWrt:/# sysupgrade /tmp/openwrt-ar71xx-dir825.bin
WOW AMAZING!!! I never thought about that!!! Thanks for your tips Now, I can fix my router in a no network state!!
Hi! Great manual!
I tried it out but when trying to run ‘lrz -Z’ on the target, I get ‘segmentation fault’.
Could it be related to the fact that you didn’t mention the need for ‘stty’ command?
I mean, before the output.txt transfer loop, there is a need to set the baudrate to 115200.
Something like that:
$ stty -F /dev/ttyUSB0 115200
Thanks in advance,
Yechiel
Hi Yechiel,
Thank you very much for your comment. It is nice to know it was useful for you!
Are you sure the “segmentation fault” was caused by wrong baudrate? When you executed stty the issue disappeared? BR, Alan
oi Acassis, gostei muito do artigo, eu estou com um problema não consigo fazer a transferência do arquivo texto em hexadecimal ocorre erro trava, eu não uso o linux tem algum programa que faça isso no windows ? se possível fazer um vídeo ou recomendar um, grato
Oi Caique, provavelmente o erro ocorre porque a sequencia de comandos foi digitada de forma errada. Não existe um programa que faça isso automaticamente, nem no Linux e nem no Windows. Você vai ter que entrar na água pra aprender a nadar. Abraços!
oi Acassis, estou no terminal linux o script, o script voce coloca por inteiro porque meu terminal tem um limite de caracteres
Oi Caique,
mesmo com o limite de caracteres se você continuar digitando o comando continuará na linha de baixo. Ou então use um terminal em modo gráfico e redimensione a tela para caber mais caracteres. Abs.
Know this article is from a long time ago but wanted to say that you helped me out a ton today. Flashed an OpenWRT update that killed the LAN/WAN interfaces a while back–oops. Then had to solder pins to the JTAG interface to get into serial and transfer a new image to flash. Even after all these years your article is still the most helpful and easy to follow on getting files copied over without initially having zmodem etc. Hope you’re still continuing to help people out.
Hi Julia, nice to hear it! I hope you got your router working fine with OpenWRT again. I also document these things because I know it could help someone. BR, Alan
Hello, Thanks for the nice trick, I had used this steps to copy lrz into my embedded terminal.
To receive the file inside the target, i had used ‘cat > filetobereceived.txt’ inside target and sent the file from host machine using teraterm ‘Send file ‘ option.
Hi Yuva Raj, very nice! I’m glad to know these tips helped you! I think using minicom ascii transfer also should work on Linux. I will try it later! Thanks for your comment.
Thank you Alan for helping me rescue my OpenWrt router!
Your ASCII sending command didn’t work for me. It seems to assume that the last line is a multiple of 16 bytes?
But I found [1] you can also use “ascii-xfr” (part of the minicom package) for this purpose.
On the receiving side “cat > lrz.txt” would have to be used. But on my router I had the issue that something [2] was making the Ctrl+C (needed after transfer completion) being ignored. So I used a little timer script to stop the receiving program (didn’t work with cat due to the >, so used tee).
To summarize getting lrz onto the router:
– lrz => output.txt conversion like shown by you
– $ picocom -b 115200 –send-cmd “ascii-xfr -snv” /dev/ttyUSB0
– router# cd /tmp
– router# $(sleep 60 && killall tee) &
– router# tee lrz.txt
– Ctrl+A Ctrl+S output.txt
– output.txt => lrz conversion like shown by you
And finally I also used picocom’s send command feature for transfering the firmware:
– $ picocom -b 115200 –send-cmd “sz –zmodem -vv” /dev/ttyUSB
– router# ./lrz -Z
– Ctrl+A Ctrl+S firmware.bin
– sysupgrade 🙂
(No need for the sleep+killall trick here, because lrz ends when the transfer ends.)
Hope this helps someone.
[1] https://unix.stackexchange.com/a/296752
[2] http://lists.busybox.net/pipermail/busybox/2003-April/042310.html
You are welcome Mathias! It nice to know you fixed your router. In fact I miss USB Firmware Update (DFU) for these router. It could be very useful, but also very dangerous if someone got physical access to your modem and want to modify it.