tl-wr802n v1: 那个唯一的reset按键

tl-wr802n v1是一个很有意思的路由器,可惜:

- 只有一个网口,而且使用OpenWrt 15.05 tl-wr841n v9固件,默认是WLAN口;软件问题还好解决。

-无线信号实在是太差了(辐射小?)。硬伤啊!!!

 

这里:

  1. bootloader(tuboot.bin)使用tplink官网提供的GPL代码编译出来的bootloader
  2. firmware使用的是OpenWrt官方固件:openwrt-15.05-ar71xx-generic-tl-wr841n-v9-squashfs-factory.bin

 

  • 在bootloader阶段:

如果一直按着,就会进行firmware upgrade模式,串口有如下log:

athrs27_phy_setup ATHR_PHY_CONTROL 0 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 0 :10
athrs27_phy_setup ATHR_PHY_CONTROL 1 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 1 :10
athrs27_phy_setup ATHR_PHY_CONTROL 2 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 2 :10
athrs27_phy_setup ATHR_PHY_CONTROL 3 :1000
athrs27_phy_setup ATHR_PHY_SPEC_STAUS 3 :10
eth1 up
eth0, eth1
Setting 0x181162c0 to 0x58b1a100
is_auto_upload_firmware=1
eth1 link down
eth0 link down
Using eth1 device
TFTP from server 192.168.0.66; our IP address is 192.168.0.86
Filename 'wr841nv10_tp_recovery.bin'.
Load address: 0x80800000
Loading: T T T 
Retry count exceeded; starting again
## Booting image at 9f020000 ...
   Uncompressing Kernel Image ... OK

这时,你可以搭一个简单的tftp server, 将server的ip设为192.168.0.66, 在tftp server的根目录放上wr841nv10_tp_recovery.bin文件,就可以更新Flash中的固件了。

[2016-01-28 20:39:40]

路由器与RPi 2B通过网线直连,并且将RPi 2B的ip地址设置成192.168.0.66, 通过tcpdump命令可以看到如下信息:

$ tcpdump -A -v
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
07:34:07.437841 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.0.66 tell 192.168.0.86, length 46
.............A...V.........B..................
07:34:07.437970 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.0.66 is-at b8:27:eb:d1:19:8a (oui Unknown), length 28
.........'.......B.....A...V
07:34:07.438105 IP (tos 0x0, ttl 255, id 32, offset 0, flags [DF], proto UDP (17), length 72)
    192.168.0.86.2140 > 192.168.0.66.tftp:  44 RRQ "wr841nv10_tp_recovery.bin" octet timeout 2
E..H. @........V...B.\.E.4....wr841nv10_tp_recovery.bin.octet.timeout.2.
07:34:07.439731 IP (tos 0x0, ttl 64, id 27840, offset 0, flags [DF], proto UDP (17), length 47)
    192.168.0.66.33987 > 192.168.0.86.2140: UDP, length 19
E../l.@.@.L....B...V...\........File not found.
07:34:07.912177 IP (tos 0x0, ttl 64, id 46515, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.51932 > localhost.domain: 27411+ PTR? 66.0.168.192.in-addr.arpa. (43)
E..G..@.@..............5.3.Fk............66.0.168.192.in-addr.arpa.....
07:34:07.912271 IP (tos 0xc0, ttl 64, id 58309, offset 0, flags [none], proto ICMP (1), length 99)
    localhost > localhost: ICMP localhost udp port domain unreachable, length 79
        IP (tos 0x0, ttl 64, id 46515, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.51932 > localhost.domain: 27411+ PTR? 66.0.168.192.in-addr.arpa. (43)
E..c....@.............F.....E..G..@.@..............5.3.Fk............66.0.168.192.in-addr.arpa.....
07:34:07.912456 IP (tos 0x0, ttl 64, id 46516, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.40693 > localhost.domain: 27411+ PTR? 66.0.168.192.in-addr.arpa. (43)
E..G..@.@..............5.3.Fk............66.0.168.192.in-addr.arpa.....
07:34:07.912502 IP (tos 0xc0, ttl 64, id 58310, offset 0, flags [none], proto ICMP (1), length 99)
    localhost > localhost: ICMP localhost udp port domain unreachable, length 79
        IP (tos 0x0, ttl 64, id 46516, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.40693 > localhost.domain: 27411+ PTR? 66.0.168.192.in-addr.arpa. (43)
E..c....@.............r.....E..G..@.@..............5.3.Fk............66.0.168.192.in-addr.arpa.....
07:34:07.921346 IP (tos 0x0, ttl 64, id 46517, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.35422 > localhost.domain: 59892+ PTR? 86.0.168.192.in-addr.arpa. (43)
E..G..@.@............^.5.3.F.............86.0.168.192.in-addr.arpa.....
07:34:07.921406 IP (tos 0xc0, ttl 64, id 58311, offset 0, flags [none], proto ICMP (1), length 99)
    localhost > localhost: ICMP localhost udp port domain unreachable, length 79
        IP (tos 0x0, ttl 64, id 46517, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.35422 > localhost.domain: 59892+ PTR? 86.0.168.192.in-addr.arpa. (43)
E..c....@..............7....E..G..@.@............^.5.3.F.............86.0.168.192.in-addr.arpa.....
07:34:07.921542 IP (tos 0x0, ttl 64, id 46518, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.44912 > localhost.domain: 59892+ PTR? 86.0.168.192.in-addr.arpa. (43)
E..G..@.@............p.5.3.F.............86.0.168.192.in-addr.arpa.....
07:34:07.921593 IP (tos 0xc0, ttl 64, id 58312, offset 0, flags [none], proto ICMP (1), length 99)
    localhost > localhost: ICMP localhost udp port domain unreachable, length 79
        IP (tos 0x0, ttl 64, id 46518, offset 0, flags [DF], proto UDP (17), length 71)
    localhost.44912 > localhost.domain: 59892+ PTR? 86.0.168.192.in-addr.arpa. (43)
E..c....@..............$....E..G..@.@............p.5.3.F.............86.0.168.192.in-addr.arpa.....
07:34:10.637780 IP (tos 0x0, ttl 255, id 33, offset 0, flags [DF], proto UDP (17), length 72)
    192.168.0.86.2140 > 192.168.0.66.tftp:  44 RRQ "wr841nv10_tp_recovery.bin" octet timeout 2
E..H.!@........V...B.\.E.4....wr841nv10_tp_recovery.bin.octet.timeout.2.
07:34:10.639420 IP (tos 0x0, ttl 64, id 27956, offset 0, flags [DF], proto UDP (17), length 47)
    192.168.0.66.35890 > 192.168.0.86.2140: UDP, length 19
E../m4@.@.K....B...V.2.\........File not found.
07:34:12.440413 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 1
~

而在路由器端的串口log, 也可以看到如下信息:

TFTP from server 192.168.0.66; our IP address is 192.168.0.86
Filename 'wr841nv10_tp_recovery.bin'.
Load address: 0x80800000
Loading: *^H
TFTP error: 'File not found' (1)
Starting again

T
TFTP error: 'File not found' (1)
Starting again

T
TFTP error: 'File not found' (1)
Starting again

T
TFTP error: 'File not found' (1)
Starting again


Retry count exceeded; starting again
## Booting image at 9f020000 ...
   Uncompressing Kernel Image ... OK

NOTE:

从相关的代码上看,文件下载成功之后,会去检查固件的版本信息是不是与Flash中的一致,不一致不会进行固件更新。

  • 在boot阶段:

从串口中可以看到如下log:

[    5.650000] random: procd urandom read with 8 bits of entropy available
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
[    8.990000] jffs2: notice: (345) jffs2_build_xattr_subsystem: complete building xattr subsystem, 0 of xdatum (0 unchecked, 0 orphan) and 0 of xref (0 dead, 0 orphan) found.
[    9.010000] mount_root: switching to jffs2 overlay

这时候,如果你短按一下这个reset按键,就可以进入failsafe模式,可以从串口中看到如下log:

Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
- failsafe button reset was pressed -
- failsafe -


BusyBox v1.23.2 (2015-07-25 15:09:46 CEST) built-in shell (ash)

ash: can't access tty; job control turned off
  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 CHAOS CALMER (15.05, r46767)
 -----------------------------------------------------
  * 1 1/2 oz Gin            Shake with a glassful
  * 1/4 oz Triple Sec       of broken ice and pour
  * 3/4 oz Lime Juice       unstrained into a goblet.
  * 1 1/2 oz Orange Juice
  * 1 tsp. Grenadine Syrup
 -----------------------------------------------------
================= FAILSAFE MODE active ================
special commands:
* firstboot          reset settings to factory defaults
* mount_root     mount root-partition with config files

after mount_root:
* passwd                         change root's password
* /etc/config               directory with config files

for more help see:
http://wiki.openwrt.org/doc/howto/generic.failsafe
=======================================================

root@(none):/# 

从log中你可以看到, 这时,你可以执行firstboot命令进行恢复出厂设置,或者是执行 mount_root命令,挂载根文件系统。在挂载根文件系统之后,你就可以修改root的密码,也可以修改相关的配置(/etc/config/)。

相关的文档可以参考:https://wiki.openwrt.org/doc/howto/generic.failsafe

NOTE:

当然,你也可以通过监听udp端口来确定按下的时机,具体请看官方文档:

$ tcpdump -Ani eth0 port 4919 and udp

[2016-01-28 20:36:05]NOTE:

tl-wr802n v1无法通过这个命令无效,使用tcpdump不会打输出failsafe的log。

从/etc/hotplug-preinit.json文件可以推断出,如果有按键按下,会去执行/etc/rc.button/failsafe:

root@OpenWrt-wr802n-v1:/etc# cat hotplug-preinit.json 
[
    ...
	[ "if",
		[ "and",
			[ "eq", "SUBSYSTEM", "button" ],
		],
		[ "exec", "/etc/rc.button/failsafe" ]
	],
]

而/etc/rc.button/failsafe会去做:

root@OpenWrt-wr802n-v1:/etc# cat rc.button/failsafe 
#!/bin/sh

[ "${TYPE}" = "switch" ] || echo ${BUTTON} > /tmp/failsafe_button

return 0

将button的名字”reset”写入到/tmp/failsafe_button, 这又有什么用呢?这得回看/lib/preinit/30_failsafe_wait:

root@OpenWrt-wr802n-v1:/lib/preinit# cat 30_failsafe_wait 
#!/bin/sh
# Copyright (C) 2006-2010 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

fs_wait_for_key () {
	local timeout=$3
	local timer
	local do_keypress
	local keypress_true="$(mktemp)"
	local keypress_wait="$(mktemp)"
	local keypress_sec="$(mktemp)"
	if [ -z "$keypress_wait" ]; then
		keypress_wait=/tmp/.keypress_wait
		touch $keypress_wait
	fi
	if [ -z "$keypress_true" ]; then
		keypress_true=/tmp/.keypress_true
		touch $keypress_true
	fi
	if [ -z "$keypress_sec" ]; then
		keypress_sec=/tmp/.keypress_sec
		touch $keypress_sec
	fi

	trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" INT
	trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" USR1

	[ -n "$timeout" ] || timeout=1
	[ $timeout -ge 1 ] || timeout=1
	timer=$timeout
	lock $keypress_wait
	{
		while [ $timer -gt 0 ]; do
			echo "$timer" >$keypress_sec
			timer=$(($timer - 1))
			sleep 1
		done
		lock -u $keypress_wait
		rm -f $keypress_wait
	} &

	echo "Press the [$1] key and hit [enter] $2"
	echo "Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level"
	# if we're on the console we wait for input
	{
		while [ -r $keypress_wait ]; do
			timer="$(cat $keypress_sec)"

			[ -n "$timer" ] || timer=1
			timer="${timer%%\ *}"
			[ $timer -ge 1 ] || timer=1
			do_keypress=""
			{
				read -t "$timer" do_keypress
				case "$do_keypress" in
				$1)
					echo "true" >$keypress_true
					;;
				1 | 2 | 3 | 4)
					echo "$do_keypress" >/tmp/debug_level
					;;
				*)
					continue;
					;;
				esac
				lock -u $keypress_wait
				rm -f $keypress_wait
			}
		done
	}
	lock -w $keypress_wait

	keypressed=1
	[ "$(cat $keypress_true)" = "true" ] && keypressed=0

	rm -f $keypress_true
	rm -f $keypress_wait
	rm -f $keypress_sec

	return $keypressed
}

failsafe_wait() {
	FAILSAFE=
	grep -q 'failsafe=' /proc/cmdline && FAILSAFE=true && export FAILSAFE
	if [ "$FAILSAFE" != "true" ]; then
		pi_failsafe_net_message=true
		preinit_net_echo "Please press button now to enter failsafe"
		pi_failsafe_net_message=false
		fs_wait_for_key f 'to enter failsafe mode' $fs_failsafe_wait_timeout && FAILSAFE=true
		[ -f "/tmp/failsafe_button" ] && FAILSAFE=true && echo "- failsafe button "`cat /tmp/failsafe_button`" was pressed -"
		[ "$FAILSAFE" = "true" ] && export FAILSAFE && touch /tmp/failsafe
	fi
}

boot_hook_add preinit_main failsafe_wait

这里会去检查/tmp/failsafe_button是否存在,如果存在的话,会将FAILSAFE设为true, 并将相关log显示在串口log中。

NOTE:

关于failsafe等待的时间(2秒)及其他相关信息,请看/etc/preinit文件:

fs_failsafe_ifname=
fs_failsafe_ip=192.168.1.1
fs_failsafe_broadcast=192.168.1.255
fs_failsafe_netmask=255.255.255.0

fs_failsafe_wait_timeout=2
  • 在系统运行阶段:

短按(小于5秒):可以重启系统,在串口log中可以看到REBOOT

长按(需要大于5秒):恢复出厂设置。小心,如果不小心长按了,不想后悔记得先断电!

NOTE:

系统正常运行时,button的功能由/etc/hotplug.json决定:

root@OpenWrt-wr802n-v1:/etc# cat hotplug.json 
[
    ...
	[ "if",
		[ "and",
			[ "has", "BUTTON" ],
			[ "eq", "SUBSYSTEM", "button" ],
		],
		[ "exec", "/etc/rc.button/%BUTTON%" ]
	],
    ...
]

在/etc/rc.button/文件夹中包含failsafe, power, reset和rfkill这几个文件。

先看一下/etc/rc.button/power, 会执行关机命令:

root@OpenWrt-wr802n-v1:/etc# cat rc.button/power 
#!/bin/sh

[ "${ACTION}" = "released" ] || exit 0

exec /sbin/poweroff

return 0

再看一下/etc/rc.button/reset, 会执行重启或者是恢复出厂设置:

root@OpenWrt-wr802n-v1:/etc# cat rc.button/reset 
#!/bin/sh

[ "${ACTION}" = "released" ] || exit 0

. /lib/functions.sh

logger "$BUTTON pressed for $SEEN seconds"

if [ "$SEEN" -lt 1 ]
then
	echo "REBOOT" > /dev/console
	sync
	reboot
elif [ "$SEEN" -gt 5 ]
then
	echo "FACTORY RESET" > /dev/console
	jffs2reset -y && reboot &
fi

return 0

[2016-01-28 20:49:44]NOTE:

在failsafe模式下,reset button是不起作用的。

 

这里其实应该先去看一下开机流程相关的文档的:

  1. https://wiki.openwrt.org/doc/techref/process.boot
  2. https://wiki.openwrt.org/doc/techref/preinit_mount

《tl-wr802n v1: 那个唯一的reset按键》有5个想法

  1. 朋友,您好
    802N V1刷了管方的lede 17.10
    按住reset不能恢复出厂设置
    解决思路是什么?你能帮帮我吗
    感谢!

    1. 1. 路由器与电脑通过网线直连
      2. 设置电脑的IP地址为192.168.0.66
      3. 电脑上建tftp 服务器,将固件命名为wr841nv10_tp_recovery.bin, 放置在根目录
      关于固件,可以参考https://www.brobwind.com/archives/459
      从官网下载固件http://service.tp-link.com.cn/detail_download_2208.html
      应该可以升级成功。

发表评论

电子邮件地址不会被公开。 必填项已用*标注