D-Link DWL Series of Business Access Points
Qualcomm-based devices built by Cameo
Model Overview
Model | Wireless | SoC / WiFi | Flash | RAM | Case |
---|---|---|---|---|---|
DWL-6620APS | AC1300 Wave2 | IPQ4019 | ? | ? | indoor, built-in antennas |
DWL-7620AP | AC2200 Wave2 Tri-Band | IPQ4019 + QCA9886 | 128+4 | 512 | indoor, built-in antennas |
DWL-8620AP | AC2600 Wave2 | IPQ8064 + 2x QCA???? | 128+4 | 512 | indoor, built-in antennas |
DWL-8720AP | AC1300 Wave2 | IPQ4019 | ? | ? | outdoor IP67, 2x dual band N antennas |
DWL-X8630AP | AX3600 | IPQ8072A + QCN5024 + QCN5054 | ? | ? | indoor, built-in antennas |
Serial Console
The devices have an RJ-45 console port (Cisco-style light blue cable), using RS-232 levels at 115200.
Flash Layout
Most (all?) devices have 4 MiB of SPI NOR containing the bootloader and 128 MiB NAND, split into 3 UBI regions:
0x0000000 - 0x2000000 32 MiB 0x2000000 - 0x4000000 32 MiB 0x4000000 - 0x8000000 64 MiB
The first two seem to be for dual boot and contain kernel, ubi_rootfs and rootfs_data volumes each:
(IPQ40xx) # set mtdids nand0=nand0 && set mtdparts mtdparts=nand0:0x2000000@0x0000000(fs),${msmparts} && ubi part fs && ubi info l UBI: mtd2 is detached from ubi0 Creating 1 MTD partitions on "nand0": 0x000000000000-0x000002000000 : "mtd=0" UBI: attaching mtd2 to ubi0 UBI: physical eraseblock size: 131072 bytes (128 KiB) UBI: logical eraseblock size: 126976 bytes UBI: smallest flash I/O unit: 2048 UBI: VID header offset: 2048 (aligned 2048) UBI: data offset: 4096 UBI: attached mtd2 to ubi0 UBI: MTD device name: "mtd=0" UBI: MTD device size: 32 MiB UBI: number of good PEBs: 256 UBI: number of bad PEBs: 0 UBI: max. allowed volumes: 128 UBI: wear-leveling threshold: 4096 UBI: number of internal volumes: 1 UBI: number of user volumes: 4 UBI: available PEBs: 38 UBI: total number of reserved PEBs: 218 UBI: number of PEBs reserved for bad PEB handling: 2 UBI: max/mean erase counter: 6/2 UBI: volume information dump: UBI: vol_id 0 UBI: reserved_pebs 38 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 6 UBI: usable_leb_size 126976 UBI: used_ebs 38 UBI: used_bytes 4825088 UBI: last_eb_bytes 126976 UBI: corrupted 0 UBI: upd_marker 0 UBI: name kernel UBI: volume information dump: UBI: vol_id 1 UBI: reserved_pebs 137 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 10 UBI: usable_leb_size 126976 UBI: used_ebs 137 UBI: used_bytes 17395712 UBI: last_eb_bytes 126976 UBI: corrupted 0 UBI: upd_marker 0 UBI: name ubi_rootfs UBI: volume information dump: UBI: vol_id 2 UBI: reserved_pebs 36 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 6 UBI: usable_leb_size 126976 UBI: used_ebs 36 UBI: used_bytes 4571136 UBI: last_eb_bytes 126976 UBI: corrupted 0 UBI: upd_marker 0 UBI: name rootfs UBI: volume information dump: UBI: vol_id 3 UBI: reserved_pebs 1 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 11 UBI: usable_leb_size 126976 UBI: used_ebs 1 UBI: used_bytes 126976 UBI: last_eb_bytes 126976 UBI: corrupted 0 UBI: upd_marker 0 UBI: name rootfs_data UBI: volume information dump: UBI: vol_id 2147479551 UBI: reserved_pebs 2 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 13 UBI: usable_leb_size 126976 UBI: used_ebs 2 UBI: used_bytes 253952 UBI: last_eb_bytes 2 UBI: corrupted 0 UBI: upd_marker 0 UBI: name layout volume (IPQ40xx) #
The last region contains a volume named flash2:
(IPQ40xx) # set mtdparts mtdparts=nand0:0x4000000@0x4000000(fs),${msmparts} && ubi part fs && ubi info l UBI: mtd2 is detached from ubi0 Creating 1 MTD partitions on "nand0": 0x000004000000-0x000008000000 : "mtd=0" UBI: attaching mtd2 to ubi0 UBI: physical eraseblock size: 131072 bytes (128 KiB) UBI: logical eraseblock size: 126976 bytes UBI: smallest flash I/O unit: 2048 UBI: VID header offset: 2048 (aligned 2048) UBI: data offset: 4096 UBI: attached mtd2 to ubi0 UBI: MTD device name: "mtd=0" UBI: MTD device size: 64 MiB UBI: number of good PEBs: 512 UBI: number of bad PEBs: 0 UBI: max. allowed volumes: 128 UBI: wear-leveling threshold: 4096 UBI: number of internal volumes: 1 UBI: number of user volumes: 1 UBI: available PEBs: 35 UBI: total number of reserved PEBs: 477 UBI: number of PEBs reserved for bad PEB handling: 5 UBI: max/mean erase counter: 1/0 UBI: volume information dump: UBI: vol_id 0 UBI: reserved_pebs 468 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 6 UBI: usable_leb_size 126976 UBI: used_ebs 468 UBI: used_bytes 59424768 UBI: last_eb_bytes 126976 UBI: corrupted 0 UBI: upd_marker 0 UBI: name flash2 UBI: volume information dump: UBI: vol_id 2147479551 UBI: reserved_pebs 2 UBI: alignment 1 UBI: data_pad 0 UBI: vol_type 3 UBI: name_len 13 UBI: usable_leb_size 126976 UBI: used_ebs 2 UBI: used_bytes 253952 UBI: last_eb_bytes 2 UBI: corrupted 0 UBI: upd_marker 0 UBI: name layout volume (IPQ40xx) #
Factory Image Encryption
The factory images use the same format as a few other D-Link devices built by Cameo, i.e. DIR-1750 and DIR-1950:
Two strings from the image header are used to generate a key using hmac, which is then used for openssl AES-256 encryption.
For DWL-7620AP this would be:
dwl-7620ap DWL7620QCA4019-AP-170825-00
$ echo -n dwl-7620ap | openssl dgst -sha1 -hmac DWL7620QCA4019-AP-170825-00 | cut -d ' ' -f 2 7e3fe8984366535d96e702021c998fd9d72a56ed $ openssl aes-256-cbc -d -md md5 -in DWL-7620AP_A1_FW4.7.3.0B102C_noheaders.bin -out decrypted.bin -k 7e3fe8984366535d96e702021c998fd9d72a56ed
However for newer devices like DWL-8620AP and DWL-X8630AP, aes-256-ecb is used instead of cbc, e.g.:
$ echo -n dwl-8620ap | openssl dgst -sha1 -hmac DWL8620QCA8064-AP-170802-00 | cut -d ' ' -f 2 a905d17c129e61aeb7d78502d2f085986832f36c $ openssl aes-256-ecb -d -md md5 -in DWL-8620AP_A1_FW4730B101C_noheaders.bin -out DWL-8620AP_A1_FW4730B101C_decrypted.bin -k a905d17c129e61aeb7d78502d2f085986832f36c
Proof-of concept factory image creation is implemented in https://github.com/openwrt/openwrt/commit/90125b5cb9dc9989ca964fe793db95bdfc561565