My Cloud PR4100 Firmware Analysis


#224

Doing stack traces is not something I’m accustomed to doing, so wrapping my head around it all has been somewhat challenging.

# strace -f -v -o /shares/Public/wdtms_out.txt /opt/wd/bin/wdtms -config=/etc/wd/BNFA-thermal.xml

At this point I’m reasonably certain that the /dev/i2c-8 device is used for reading system board temperatures. Information gleaned from a stack trace of the /opt/wd/bin/wdtms program revealed that the /usr/bin/i2cget program is used to read from the /dev/i2c-8 device, and that at least two (possibly more) chip addresses are read.

# i2cget
Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
  I2CBUS is an integer or an I2C bus name
  ADDRESS is an integer (0x03 - 0x77)
  MODE is one of:
    b (read byte data, default)
    w (read word data)
    c (write byte/read byte)
    Append p for SMBus PEC

-f Force access to the device even if it is already busy.
-y Disable interactive mode. Use with caution.

# i2cget -y [I2C_BUS] [CHIP_ADDRESS] [DATA_ADDRESS]

# i2cget -y 8 0x4c 0x1
0x1e (30 Decimal)

# i2cget -y 8 0x4c 0x10
0x60 (96 Decimal)

13457 open("/dev/i2c-8", O_RDWR)        = 3
13457 ioctl(3, _IOC(0, 0x07, 0x05, 0x00), 0x7ffed47eadc0) = 0
13457 ioctl(3, _IOC(0, 0x07, 0x03, 0x00), 0x4c) = 0
13457 ioctl(3, _IOC(0, 0x07, 0x20, 0x00), 0x7ffed47ead90) = 0
13457 close(3)

Information gleaned from the /opt/wd/bin/wdtms program also revealed that CPU core temperatures are read from the /sys/class/hwmon/hwmon1 device.

# grep hwmon wdtms_out.txt
13453 open("/sys/class/hwmon/hwmon1/temp3_crit_alarm", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp3_crit", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp3_input", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp4_crit_alarm", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp4_crit", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp4_input", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp5_crit_alarm", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp5_crit", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp5_input", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp3_input", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp4_input", O_RDONLY) = 4
13453 open("/sys/class/hwmon/hwmon1/temp5_input", O_RDONLY) = 4

Information gleaned from the /opt/wd/bin/wdhws program indicates that the /dev/ttyS2 serial device is used for fan control, but I’m having trouble identifying the exact hexadecimal addresses and values involved. It’s important to have the raw values so that the information may be used with any programming language, and be free of dependencies upon WD compiled binary files.

# strace -f -v -o /shares/Public/wdhws_out.txt /opt/wd/bin/wdhws -config=/etc/wd/sprite-wdhw.xml


#226

These are fan related commands I see during startup of wdhws.

get config with 'CFG'       --> CFG=02
set config with 'CFG=2'
set DLS with 'DLS=f'     
get version with 'VER'      --> VER=WD BBC v01
get ISR with 'ISR'          --> ISR=00
set IMR with 'IMR=FF'
get status with 'STA'       --> STA=6a
get temperature with 'TMP'  --> TMP=22 ... 34 degrees celcius

Then it sets fan speed and checks RPM + status.

Polling all possible 3 letter fields results in:

BKL=3C
BLK=00
CFG=02
DLB=00
ECH=00
FAN=14
IMR=ff
ISR=00
LED=02
PLS=00
RPM=01fe
STA=6a
TAC=0011
TMP=23   ---> clearly temperature

Then suddenly I got this after sending 'UPD'

========= WDPMC Update Menu v1.0 =============
Reset PMC -------------------------------- 0
Write Image To PMC Internal Flash -------- 1
Read Image From PMC Internal Flash ------- 2
Execute The New Program ------------------ 3
==============================================
Invalid Number ! ==> The number should be either 1, 2 or 3

I guess I bricked something. Be careful not to spam the poor box with unknown commands!


#228

That:'s unfortunate, yet interesting.

It seems that you’ve stumbled on a chip programming menu. The UPD command obviously means “Update”, but judging by the menu options, it does not look like the firmware on the chip has been altered… yet. My guess would be option 0 or 3, but not option 1 or 2. Assuming that you can interact with the chip, the command may simply be a number, or it may take the form of 'UPD=0\n' like other commands.

This also exposes a significant hardware vulnerabiity, where malicious code could easily render the PMC chip inoperative.


#229

I had a script running for about an hour that tried all 3 letter combinations… I’ll reboot when I get home.


#231

What a relief. When you do a full power down and pulling the power cable, the module is reloaded.
No damage was done :slight_smile:


#233

Honestly I care little about that chip :slight_smile:
ZFS here I come!


#245

Linux allocated devices (4.x+ version):

https://www.kernel.org/doc/html/v4.11/admin-guide/devices.html

Filesystem Hierarchy Standard:

http://www.pathname.com/fhs/pub/fhs-2.3.html

Linux From Scratch:

http://www.linuxfromscratch.org/lfs/view/6.1/index.html

Embedded Linux Applications:

https://www.ibm.com/developerworks/library/l-embl/index.html


#247

Every Linux distribution has numerous programs, and all of them originate from source code packages. Some packages have many programs, and some packages contain a single program.

util-linux-2.31.tar.gz

addpart agetty blkdiscard blkid blockdev cal cfdisk chcpu chrt col colcrt 
colrm column ctrlaltdel delpart dmesg eject fallocate fdformat fdisk findfs 
findmnt flock fsck fsck.cramfs fsck.minix fsfreeze fstrim getopt hexdump 
hwclock i386 ionice ipcmk ipcrm ipcs isosize kill last lastb ldattach linux32 
linux64 logger look losetup lsblk lscpu lsipc lslocks lslogins mcookie mesg 
mkfs mkfs.bfs mkfs.cramfs mkfs.minix mkswap more mount mountpoint namei 
nsenter partx pg pivot_root prlimit raw readprofile rename renice 
resizepart rev rtcwake script scriptreplay setarch setsid setterm sfdisk 
sulogin swaplabel swapoff swapon switch_root tailf taskset ul umount 
uname26 unshare utmpdump uuidd uuidgen wall wdctl whereis wipefs 
x86_64 zramctl

coreutils-8.28.tar.gz

arch b2sum base32 base64 basename cat chcon chgrp chmod chown chroot cksum
comm coreutils cp csplit cut date dd df dir dircolors dirname du echo env
expand expr factor false fmt fold groups head hostid hostname id install
join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl
nohup nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd
readlink realpath rm rmdir runcon seq sha1sum sha224sum sha256sum sha384sum
sha512sum shred shuf sleep sort split stat stdbuf stty sum sync tac tail
tee test timeout touch tr true truncate tsort tty uname unexpand uniq
unlink uptime users vdir wc who whoami yes

e2fsprogs-1.43.7.tar.gz

badblocks chattr compile_et debugfs dumpe2fs e2freefrag e2fsck e2image 
e2label e2undo e4defrag filefrag fsck.ext2 fsck.ext3 fsck.ext4 fsck.ext4dev 
logsave lsattr mk_cmds mke2fs mkfs.ext2 mkfs.ext3 mkfs.ext4 mkfs.ext4dev 
mklost+found resize2fs tune2fs

binutils-2.29.tar.gz

ld as addr2line ar c++filt dlltool gold gprof nlmconv nm objcopy objdump 
ranlib readelf size strings strip indmc windres 

findutils-4.5.19.tar.gz

code find locate oldfind updatedb xargs

nano-2.9.1.tar.gz

nano

In time, I may create a list, simply to make things easier for anyone who may choose to take the road less traveled. Note that nano is included in my example because I think vi is a royal pain to use.


#250

LCD Backlight Brightness (BKL):

0x00 = 000 -> 000.0% Brightness (Min)
0x3C = 060 -> 023.5% Brightness (Default)
0x80 = 128 -> 050.2% Brightness
0xFF = 255 -> 100.0% Brightness (Max)

Type: Get and Set
Note: Level 0-255

# echo -ne 'BKL=00\r' > /dev/ttyS2

LCD Display Text (LN1, LN2):

Type: Set only
Note: 16 Characters Max Per Line

# echo -ne 'LN1=XXXXXXXXXXXXXXXX\r' > /dev/ttyS2
# echo -ne 'LN2=XXXXXXXXXXXXXXXX\r' > /dev/ttyS2

Fan Speed (FAN):

0x00 = 0x0000 ->    0 RPM
0x05 = 0x00F0 ->  240 RPM
0x10 = 0x01A4 ->  420 RPM
0x15 = 0x023A ->  570 RPM
0x20 = 0x0348 ->  840 RPM
0x25 = 0x03C0 ->  960 RPM
0x30 = 0x04CE -> 1230 RPM
0x35 = 0x0546 -> 1350 RPM
0x40 = 0x0636 -> 1590 RPM
0x45 = 0x0690 -> 1680 RPM
0x50 = 0x0780 -> 1920 RPM
0x55 = 0x07BC -> 1980 RPM
0x60 = 0x0870 -> 2160 RPM

Type: Get and Set
Note: Level 0-64

# echo -ne 'FAN=25\r' > /dev/ttyS2

Fan Speed (TAC):

0x00 = 0x0000 -> 000
0x05 = 0x0009 -> 009
0x10 = 0x000E -> 014
0x15 = 0x0013 -> 019
0x20 = 0x001C -> 028
0x25 = 0x0021 -> 033
0x30 = 0x0029 -> 041
0x35 = 0x002D -> 045
0x40 = 0x0035 -> 053
0x45 = 0x0039 -> 057
0x50 = 0x0040 -> 064
0x55 = 0x0043 -> 067
0x60 = 0x0049 -> 073

Type: Get only
Note: RPM = ((TAC / 2) * 60)

# echo -ne 'TAC\r' > /dev/ttyS2

Buttons Pressed (ISR):

0x00 -> No Buttons Pressed
0x08 -> USB Copy Button Pressed
0x20 -> LCD Up Button Pressed
0x40 -> LCD Down Button Pressed

Type: Get only
Note: LCD and USB
Note: After boot ISR=10, reset to ISR=00 before use
Note: ISR resets to 0x00 after value retrieved
Note: ALERT sent when a button is pressed

# echo -ne 'ISR\r' > /dev/ttyS2

LED Configuration (LED, BLK):

0x00 = 0000 0000 -> Power All Off, USB All Off
0x01 = 0000 0001 -> Power Blue On
0x02 = 0000 0010 -> Power Red On
0x04 = 0000 0100 -> Power Green On
0x08 = 0000 1000 -> USB Red On
0x09 = 0000 1001 -> USB Red On, Power Blue On
0x0A = 0000 1010 -> USB Red On, Power Red On
0x0C = 0000 1100 -> USB Red On, Power Green On
0x10 = 0001 0000 -> USB Blue On
0x11 = 0001 0001 -> USB Blue On, Power Blue On
0x12 = 0001 0010 -> USB Blue On, Power Red On
0x14 = 0001 0100 -> USB Blue On, Power Green On
0x1F = 0001 1111 -> Power All On, USB All On

Type: Get and Set
Note: USB and Power LEDs
Note: LED is Solid
Note: BLK is Blink
Note: Set LED=00 and PLS=00 before setting BLK
Note: Set BLK=00 and PLS=00 before setting LED

echo -ne "LED=00\r" > /dev/ttyS2
echo -ne "BLK=00\r" > /dev/ttyS2

LED Configuration Bits (LED, BLK):

0 0 0 0  0 0 0 1 --> 0x01 (Hex)
- - - -  - - - -
| | | |  | | | |
| | | |  | | | +---> Power Blue
| | | |  | | +-----> Power Red
| | | |  | +-------> Power Green
| | | |  +---------> USB Red
| | | +------------> USB Blue
| | +--------------> Unused
| +----------------> Unused
+------------------> Unused

LED Pulse (PLS):

0x00 -> LED Pulse Off
0x01 -> LED Pulse On

Type: Get and Set
Note: Power LED Only
Note: Set LED=00 and BLK=00 before setting PLS

# echo -ne 'PLS=00\r' > /dev/ttyS2

Drive Status (DE0):

0x0F = 0000 1111 -> hd1,hd2,hd3,hd4
0x1F = 0001 1111 -> hd2,hd3,hd4
0x2F = 0010 1111 -> hd1,hd3,hd4
0x3F = 0011 1111 -> hd3,hd4
0x4F = 0100 1111 -> hd1,hd2,hd4
0x5F = 0101 1111 -> hd2,hd4
0x6F = 0110 1111 -> hd1,hd4
0x7F = 0111 1111 -> hd4
0x8F = 1000 1111 -> hd1,hd2,hd3
0x9F = 1001 1111 -> hd2,hd3
0xAF = 1010 1111 -> hd1,hd3
0xBF = 1011 1111 -> hd3
0xCF = 1100 1111 -> hd1,hd2
0xDF = 1101 1111 -> hd2
0xEF = 1110 1111 -> hd1
0xFF = 1111 1111 -> None

Type: Get and Set
Note: Red LED On/Off
Note: Use with caution
Note: Zeros in right half of byte powers down drive(s)
Note: DLC/DLS are inverse of DE0

# echo -ne 'DE0=FF\r' > /dev/ttyS2

Drive Power (DE0):

0x00 - 0000 0000 -> hd1,hd2,hd3,hd4
0x01 - 0000 0001 -> hd1,hd2,hd3
0x02 - 0000 0010 -> hd1,hd3,hd4
0x03 - 0000 0011 -> hd3,hd4
0x04 - 0000 0100 -> hd1,hd2,hd4
0x05 - 0000 0101 -> hd2,hd4
0x06 - 0000 0110 -> hd1,hd4
0x07 - 0000 0111 -> hd4
0x08 - 0000 1000 -> hd2,hd3,hd4
0x09 - 0000 1001 -> hd2,hd3
0x0A - 0000 1010 -> hd1,hd3
0x0B - 0000 1011 -> hd3
0x0C - 0000 1100 -> hd1,hd2
0x0D - 0000 1101 -> hd2
0x0E - 0000 1110 -> hd1
0x0F - 0000 1111 -> None

Type: Get and Set
Note: Blue LED On/Off
Note: Use with caution
Note: Zeros in right half of byte powers down drive(s)
Note: DLC/DLS are inverse of DE0

# echo -ne 'DE0=0F\r' > /dev/ttyS2

Drive Status (DLC, DLS):

0x10 = 0001 0000 -> hd1
0x20 = 0010 0000 -> hd2
0x30 = 0011 0000 -> hd1,hd2
0x40 = 0100 0000 -> hd3
0x50 = 0101 0000 -> hd1,hd3
0x60 = 0110 0000 -> hd2,hd3
0x70 = 0111 0000 -> hd2,hd3,hd4
0x80 = 1000 0000 -> hd4
0x90 = 1001 0000 -> hd1,hd4
0xA0 = 1010 0000 -> hd2,hd4
0xB0 = 1011 0000 -> hd1,hd2,hd4
0xC0 = 1100 0000 -> hd3,hd4
0xD0 = 1101 0000 -> hd1,hd3,hd4
0xE0 = 1110 0000 -> hd1,hd2,hd3
0xF0 = 1111 0000 -> hd1,hd2,hd3,hd4

Type: Set only
Note: Red LED On/Off
Note: Use with caution
Note: Ones in right half of byte powers down drive(s)
Note: DLC/DLS are inverse of DE0
Note: Use DLC for on, or DLS for off

# echo -ne 'DLC=F0\r' > /dev/ttyS2
# echo -ne 'DLS=F0\r' > /dev/ttyS2

Drive Power (DLC, DLS):

0x01 - 0000 0001 -> hd1
0x02 - 0000 0010 -> hd2
0x03 - 0000 0011 -> hd1,hd2
0x04 - 0000 0100 -> hd3
0x05 - 0000 0101 -> hd1,hd3
0x06 - 0000 0110 -> hd2,hd3
0x07 - 0000 0111 -> hd2,hd3,hd4
0x08 - 0000 1000 -> hd4
0x09 - 0000 1001 -> hd1,hd4
0x0A - 0000 1010 -> hd2,hd4
0x0B - 0000 1011 -> hd1,hd2,hd4
0x0C - 0000 1100 -> hd3,hd4
0x0D - 0000 1101 -> hd1,hd3,hd4
0x0E - 0000 1110 -> hd1,hd2,hd3
0x0F - 0000 1111 -> hd1,hd2,hd3,hd4

Type: Set only
Note: Blue LED On/Off
Note: Use with caution
Note: Ones in right half of byte powers down drive(s)
Note: DLC/DLS are inverse of DE0
Note: Use DLC for on, or DLS for off

# echo -ne 'DLC=0F\r' > /dev/ttyS2
# echo -ne 'DLS=0F\r' > /dev/ttyS2

Drive Status and Power Bits (DE0, DLC, DLS):

0 0 0 1  0 0 0 0 --> 0x10 (Hex)
- - - -  - - - -
| | | |  | | | |
| | | |  | | | +---> hd1 Power
| | | |  | | +-----> hd2 Power
| | | |  | +-------> hd3 Power
| | | |  +---------> hd4 Power
| | | +------------> hd1 Status LED (Red)
| | +--------------> hd2 Status LED (Red)
| +----------------> hd3 Status LED (Red)
+------------------> hd4 Status LED (Red)

Drive LED Blink (DLB):

0x00 = 0000 0000 -> None
0x10 = 0001 0000 -> hd1
0x20 = 0010 0000 -> hd2
0x30 = 0011 0000 -> hd1,hd2
0x40 = 0100 0000 -> hd3
0x50 = 0101 0000 -> hd1,hd3
0x60 = 0110 0000 -> hd2,hd3
0x70 = 0111 0000 -> hd1,hd2,hd3
0x80 = 1000 0000 -> hd4
0x90 = 1001 0000 -> hd1,hd4
0xA0 = 1010 0000 -> hd2,hd4
0xB0 = 1011 0000 -> hd1,hd2,hd4
0xC0 = 1100 0000 -> hd3,hd4
0xD0 = 1101 0000 -> hd1,hd3,hd4
0xE0 = 1110 0000 -> hd2,hd3,hd4
0xF0 = 1111 0000 -> hd1,hd2,hd3,hd4

Type: Get and Set
Note: Red LED On/Off

echo -ne 'DLB=00\r' > /dev/ttyS2

Drive LED Blink Bits (DLB):

0 0 0 1  0 0 0 0 --> 0x10 (Hex)
- - - -  - - - -
| | | |  | | | |
| | | |  | | | +---> Always 0
| | | |  | | +-----> Always 0
| | | |  | +-------> Always 0
| | | |  +---------> Always 0
| | | +------------> Status, hd1 (Red LED Blink)
| | +--------------> Status, hd2 (Red LED Blink)
| +----------------> Status, hd3 (Red LED Blink)
+------------------> Status, hd4 (Red LED Blink)

Drives Present (DP0):

0x90 - 1001 0000 -> hd1,hd2,hd3,hd4 Present
0x91 - 1001 0001 -> hd2,hd3,hd4 Present
0x92 - 1001 0010 -> hd1,hd3,hd4 Present
0x93 - 1001 0011 -> hd3,hd4 Present
0x94 - 1001 0100 -> hd1,hd2,hd4 Present
0x95 - 1001 0101 -> hd2,hd4 Present
0x96 - 1001 0110 -> hd1,hd4 Present
0x97 - 1001 0111 -> hd4 Present
0x98 - 1001 1000 -> hd1,hd2,hd3 Present
0x99 - 1001 1001 -> hd2,hd3 Present
0x9A - 1001 1010 -> hd1,hd3 Present
0x9B - 1001 1011 -> hd3 Present
0x9C - 1001 1100 -> hd1,hd2 Present
0x9D - 1001 1101 -> hd2 Present
0x9E - 1001 1110 -> hd1 Present
0x9F - 1001 1111 -> No Drives Present

Type: Get only
Note: ALERT sent when a drive is inserted or removed

# echo -ne 'DP0\r' > /dev/ttyS2

Drives Present Bits (DP0):

1 0 0 1  0 0 0 0 --> 0x90 (Hex)
- - - -  - - - -
| | | |  | | | |
| | | |  | | | +---> hd1
| | | |  | | +-----> hd2
| | | |  | +-------> hd3
| | | |  +---------> hd4
| | | +------------> Bit always 1
| | +--------------> Bit always 0
| +----------------> Bit always 0
+------------------> Bit always 1

Note: 0=Present, 1=Absent

MCU Temperature (TMP):

0x1C -> 28C - 82F
0x1D -> 29C - 84F
0x1E -> 30C - 86F
0x1F -> 31C - 88F
0x20 -> 32C - 90F
0x21 -> 33C - 91F
0x22 -> 34C - 93F
0x23 -> 35C - 95F
0x24 -> 36C - 97F
0x25 -> 37C - 99F
0x26 -> 38C - 100F
0x27 -> 39C - 102F
0x28 -> 40C - 104F
0x29 -> 41C - 106F
0x30 -> 42C - 108F

Type: Get only

# echo -ne 'TMP\r' > /dev/ttyS2

Status (STA):

0x6A = 0110 1010 = 106 -> Power Cable in Jack #2
0x6B = 0110 1011 = 107 -> ???
0x6C = 0110 1100 = 108 -> Power Cable in Jack #1

Type: Get only
Response: STA=6C

# echo -ne 'STA\r' > /dev/ttyS2

Configuration (CFG):

Type: Get and Set

# echo -ne 'CFG=02\r' > /dev/ttyS2

Version (VER):

Type: Get only
Response: VER=WD BBC v01

# echo -ne 'VER\r' > /dev/ttyS2

Unknown (ECH):

Type: Get and Set
Response: ALERT

# echo -ne 'ECH=00\r' > /dev/ttyS2

Unknown (IMR):

Type: Get and Set
Response: IMR=FF

# echo -ne 'IMR=FF\r' > /dev/ttyS2

The following command puts the PMC chip into a special update or reset mode, with an interactive menu. Of all the commands one may issue, this appears to be the most dangerous. Yet, it may afford the possibility of dumping the PMC firmware for analysis.

WARNING: Using this command could potentially erase the PMC chip firmware, rendering fan control and other hardware control functions inoperative.

Update (UPD):

# echo -ne 'UPD\r' > /dev/ttyS2

========= WDPMC Update Menu v1.0 =============
Reset PMC -------------------------------- 0
Write Image To PMC Internal Flash -------- 1
Read Image From PMC Internal Flash ------- 2
Execute The New Program ------------------ 3
==============================================

[GUIDE] How to Install Debian Linux on the My Cloud PR4100 NAS
[FIRMWARE] FreeNAS on PR2100/PR4100 - updated!
#251

The rc.sh script, ran during the system init process, uses Busybox to mount everything in fstab. That’s fine, except that the script does it twice using ${MOUNT_CMD} -a, and I can’t see a logical reason for doing so.

MOUNT_CMD="busybox mount"
UMOUNT_CMD="busybox umount"

echo "initramfs: mount all in /etc/fstab"
${MOUNT_CMD} -a
sleep 1

${MOUNT_CMD} -t proc proc /proc
${MOUNT_CMD} -a

Later in the same rc.sh script, there’s a comment indicating that Busybox can’t handle LABEL mounts. This may or may not be true of older versions of Busybox, but I know for a fact that the latest version of Busybox can handle LABEL mounts.

# This one need the mount from util-linux, busybox's one can't handle LABEL
# echo "initramfs: mounting label=image.cfs partition"
# mount -t ext4 LABEL=image.cfs /usr/local/tmp

#252

The following sequence of commands were captured in a stack trace of the wdhws process as it communicates with the /dev/ttyS2 device during the boot process, from power-on, to shortly after completion. They reveal much about hardware initialization.

Command = "\r"
Command = "CFG\r"
Command = "CFG=2\r"
Command = "DLS=f\r"
Command = "VER\r"
Command = "ISR\r"
Command = "IMR=FF\r"
Command = "FAN=1E\r"
Command = "DP0\r"
Command = "TMP\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "RPM\r"
Command = "DE0\r"
Command = "FAN=14\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "LN1=Welcome to WD   \r"
Command = "RPM\r"
Command = "LN2=My Cloud PR4100 \r"
Command = "FAN=14\r"
Command = "FAN=14\r"
Command = "TMP\r"
Command = "FAN=14\r"
Command = "FAN=14\r"
Command = "FAN=14\r"
Command = "TMP\r"
Command = "FAN=14\r"
Command = "RPM\r"
Command = "FAN=14\r"
Command = "FAN=14\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "BLK\r"
Command = "BLK=1\r"
Command = "LED\r"
Command = "LED=0\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LN1=                \r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=0\r"
Command = "LN2=                \r"
Command = "LED\r"
Command = "LED=0\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LN1=Name:           \r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=0\r"
Command = "LN2=PR4100          \r"
Command = "LED\r"
Command = "LED=1\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=1\r"
Command = "LED\r"
Command = "LED=1\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=1\r"
Command = "LED\r"
Command = "LED=0\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=10\r"
Command = "BKL=0\r"
Command = "LED\r"
Command = "LED=10\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=11\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=11\r"
Command = "BLK\r"
Command = "BLK=0\r"
Command = "LED\r"
Command = "LED=11\r"
Command = "DLB\r"
Command = "DLC=10\r"
Command = "DLS=10\r"
Command = "DLB\r"
Command = "DLC=20\r"
Command = "DLS=20\r"
Command = "DLB\r"
Command = "DLC=40\r"
Command = "DLS=40\r"
Command = "DLB\r"
Command = "DLC=80\r"
Command = "DLS=80\r"
Command = "DLB\r"
Command = "DLC=10\r"
Command = "DLS=10\r"
Command = "DLB\r"
Command = "DLC=20\r"
Command = "DLS=20\r"
Command = "DLB\r"
Command = "DLC=40\r"
Command = "DLS=40\r"
Command = "DLB\r"
Command = "DLC=80\r"
Command = "DLS=80\r"
Command = "DLB\r"
Command = "DLC=10\r"
Command = "DLS=10\r"
Command = "DLB\r"
Command = "DLC=20\r"
Command = "DLS=20\r"
Command = "DLB\r"
Command = "DLC=40\r"
Command = "DLS=40\r"
Command = "DLB\r"
Command = "DLC=80\r"
Command = "DLS=80\r"
Command = "DLB\r"
Command = "DLC=10\r"
Command = "DLS=10\r"
Command = "DLB\r"
Command = "DLC=20\r"
Command = "DLS=20\r"
Command = "DLB\r"
Command = "DLC=40\r"
Command = "DLS=40\r"
Command = "DLB\r"
Command = "DLC=80\r"
Command = "DLS=80\r"
Command = "TMP\r"
Command = "FAN=14\r"
Command = "STA\r"
Command = "STA\r"
Command = "BKL=0\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "FAN=14\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "FAN=14\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "TMP\r"
Command = "RPM\r"
Command = "FAN=14\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "FAN=14\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "FAN=14\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "DP0\r"
Command = "DE0\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "STA\r"
Command = "TMP\r"
Command = "FAN=14\r"

#253

Power button events are handled via an ACPI daemon /usr/sbin/acpid originating from the acpid-2.0.23.tar.gz source code package.

/etc/acpi/default.sh

#!/bin/sh

set $*
group=${1%%/*}
action=${1#*/}
device=$2
id=$3
value=$4

log_unhandled() {
        logger "ACPI event unhandled: $*"
}

case "$group" in
        button)
                case "$action" in
                        power)
                                /etc/acpi/actions/powerbtn.sh
                                ;;

                        *)      log_unhandled $* ;;
                esac
                ;;

        *)      log_unhandled $* ;;
esac

/etc/acpi/powerbtn.sh

#!/bin/sh

cat <<EOF >/dev/console

Power button pressed. Shutting down!
EOF

# No power managment system appears to be running.  Just initiate a plain
# shutdown.
/sbin/shutdown -h now "Power button pressed"

touch /tmp/power_button

#254

The system board temperature is available via the i2c bus, where addresses 0x00, 0x01, and 0x23 clearly provide temperatures. However, only address 0x01 appears to be used by the wdtms daemon.

# cat /sys/class/i2c-dev/i2c-8/name

SMBus I801 adapter at f040

# i2cget -y 8 0x4c 0x00

0x17 = 23C =  73F
0x18 = 24C =  75F
0x19 = 25C =  77F
0x1A = 26C =  79F
0x1B = 27C =  81F
0x1C = 28C =  82F
0x1D = 29C =  84F
0x1E = 30C =  86F
0x1F = 31C =  88F
0x20 = 32C =  90F
0x21 = 33C =  91F
0x22 = 34C =  93F
0x23 = 35C =  95F
0x24 = 36C =  97F
0x25 = 37C =  99F
0x26 = 38C = 100F

# i2cget -y 8 0x4c 0x01

0x19 = 25C =  77F
0x1A = 26C =  79F
0x1B = 27C =  81F
0x1C = 28C =  82F
0x1D = 29C =  84F
0x1E = 30C =  86F
0x1F = 31C =  88F
0x20 = 32C =  90F
0x21 = 33C =  91F
0x22 = 34C =  93F
0x23 = 35C =  95F
0x24 = 36C =  97F
0x25 = 37C =  99F
0x26 = 38C = 100F
0x27 = 39C = 102F
0x28 = 40C = 104F

# i2cget -y 8 0x4c 0x23

0x1C = 28C =  82F
0x1D = 29C =  84F
0x1E = 30C =  86F
0x1F = 31C =  88F
0x20 = 32C =  90F
0x21 = 33C =  91F
0x22 = 34C =  93F
0x23 = 35C =  95F
0x24 = 36C =  97F
0x25 = 37C =  99F
0x26 = 38C = 100F
0x27 = 39C = 102F
0x28 = 40C = 104F

Temperature Variance:

      i2cbus = 8
chip-address = 0x4c
data-address = 0x00, 0x01, 0x23

0x01 < TMP (/dev/ttyS2) by +/- 3 degrees C
0x01 > 0x00 by +/- 2 degrees C
0x23 > 0x01 by +/- 2 degrees C

Address 0x10 is also used by the wdtms daemon, and the values obtained during testing show a clear pattern, but it’s purpose is not entirely clear.

# i2cget -y 8 0x4c 0x10

0x00 = 0000 0000 =   0
0x20 = 0010 0000 =  32
0x40 = 0100 0000 =  64
0x60 = 0110 0000 =  96
0x80 = 1000 0000 = 128 
0xA0 = 1010 0000 = 160
0xC0 = 1100 0000 = 192
0xE0 = 1110 0000 = 224

#256

Strings extracted from the /opt/wd/bin/wdhws -config=/etc/wd/sprite-wdhw.xml daemon.

Command:

(.*)((ACK)|(ERR))
(.*)((BKL=[[:xdigit:]]+)|(ERR))
(.*)((BLK=[[:xdigit:]]+)|(ERR))
(.*)((CFG=[[:xdigit:]]+)|(ERR))
(.*)((DE0=[[:xdigit:]]+)|(ERR))
(.*)((DLB=[[:xdigit:]]+)|(ERR))
(.*)((DP0=[[:xdigit:]]+)|(ERR))
(.*)((LED=[[:xdigit:]]+)|(ERR))
(.*)((PLS=[[:xdigit:]]+)|(ERR))
(.*)((RPM=[[:xdigit:]]+)|(ERR))
(.*)((STA=[[:xdigit:]]+)|(ERR))
(.*)((TMP=[[:xdigit:]]+)|(ERR))
(.*)((VER=WD (.*) v[[:digit:]]+)|(ERR))
(.*)(ISR=[[:xdigit:]]+)

Method:

hw_cancel_wait_for_button_change
hw_cancel_wait_for_drive_bay_change
hw_cancel_wait_for_reset
hw_get_drive_bay_status
hw_get_fan_rpm
hw_get_lcd_backlit
hw_get_led
hw_get_led_blink
hw_get_led_pulse
hw_get_pmc_version
hw_get_status
hw_get_temperature
hw_reset_button_held_at_boot
hw_set_fan_speed
hw_set_lcd
hw_set_lcd_backlit
hw_set_led
hw_set_led_blink
hw_set_led_pulse
hw_wait_for_button_change
hw_wait_for_drive_bay_change
hw_wait_for_reset

Debug:

Debug: hw_cancel_wait_for_button_change handle
Debug: hw_cancel_wait_for_drive_bay_change handle
Debug: hw_cancel_wait_for_reset handle
Debug: hw_free_unique_handle:
Debug: hw_get_drive_bay_status bay:
Debug: hw_get_led_blink:
Debug: hw_get_led_pulse:
Debug: hw_get_unique_handle:
Debug: hw_set_blink_led:
Debug: hw_set_drive_bay_power:
Debug: hw_set_lcd:
Debug: hw_set_lcd_backlit:
Debug: hw_set_led:
Debug: hw_set_pulse_led:
Debug: hw_wait_for_button_change
Debug: hw_wait_for_drive_bay_change handle
Debug: hw_wait_for_reset handle

Error - Method:

ERROR: hw_cancel_wait_for_button_change failed to get arguments
ERROR: hw_cancel_wait_for_reset failed to get handle
ERROR: hw_free_unique_handle failed to get arguments
ERROR: hw_get_drive_bay_status failed to get arguments
ERROR: hw_get_fan_rpm failed to get arguments
ERROR: hw_get_led_blink failed to get arguments
ERROR: hw_get_led_pulse failed to get arguments
ERROR: hw_get_temperature failed to get arguments
ERROR: hw_set_blink_led failed to get arguments
ERROR: hw_set_drive_bay_power to get arguments
ERROR: hw_set_fan_speed failed to get arguments
ERROR: hw_set_lcd failed to get arguments
ERROR: hw_set_lcd_backlit failed to get arguments
ERROR: hw_set_led failed to get arguments
ERROR: hw_set_pulse_led failed to get arguments
ERROR: hw_wait_for_button_change failed to get arguments
ERROR: hw_wait_for_reset failed to get arguments
ERROR: wait_for_drive_bay_change failed to get arguments
ERROR: cancel_wait_for_drive_bay_change
ERROR: notify_waiters awake for no reason

Error - Miscellaneous:

ERROR: ISR command fails - ignoring alert
ERROR: PMC communication exhausted retry(s)
ERROR: Serial Port failed to open
ERROR: Serial Port failed to set baudrate
ERROR: STA command fails - ignoring alert
ERROR: Fail disable automatic HDD power enable based on presence detection
ERROR: Fail to start alert_monitor
ERROR: Fail to start reset_monitor
ERROR: Fail turn on all drives
ERROR: failed to get PMC version
ERROR: failed to parse PMC version string

#258

hello,now I created an emmc image with the partition table information in your posts.I booted latest firmware in virtualbox but there is no network.
The GRUB bootloader in the WD firmware could not load the linux kernel ,so I used ubuntu GRUB2 and a modified grub.cfg.
The firmware seems working in virtualbox, and I can see serial outputs from the virtualbox,although lots of device not found.i got a root terminal and using ifconfig ican only see the bonding and loopback interface (there should be two more ,egiga0 and egiga1),

so I wonder how to fix the network problem
and contact me if anyone want these virtualbox images


#259

Please find a forum, such as the https://forum.doozan.com/read.php?2,34103 link, and keep posting your discoveries. Or start a free Google Blog. Would much like to see your work evolve and get some help. Please post your code collection on github. Thanks for considering.


#261

how do I get this access to my NAS.
firmware recovery in SAFE MODE
Thanks.


#262

The WD NAS devices don’t have a safe mode per se, but if you are trying to restore or reload the firmare you can generally use the reset procedure for your particular NAS device.


#263

My pro4100 is not booting any more, display shows the welcome message but stuck in blinking blue power btn. ethernet port will never go up so theres no connectivity. (BTW I removed all HD from the unit). Tried already all reset procedures with no success. is it possible to share the img of the booting usb so that I can get into recovery? You can imagine that at this point i do have no concern about fan control not working or leds not properly mapped. Just need a valid img which will allow me to boot from usb into recovery to flash the latest firmware. BTW, so far im not having success with UART port, will test later at night…


#264

Here are the rescue files. Put them on a FAT32 formatted USB drive and reinstall the firmware via the rescue wizard in the web interface.


Totally bricked PR4100 - drive LEDs blinking red?