D-Link DIR-825

Revision Supported since Model Specific Notes
A1 not supported
B1/B2 Attitude Adjustment
C1 Barrier Breaker trunk r35403 See r35401, r35402, r35403, Also see DIR-835
C2 same as C1? works with C1 images, see below
D1 not supported See Forum
E1 not supported See Forum
G1 not supported Same basic hardware as E1 (see FCC ID KA2IR825G1)

Note: B2 appears to only be different in labeling. The default firmware claims B1 and even /proc/cpuinfo claim to be B1 revisions even though the packaging and the sticker say B2.
Update!!! D1/E1 revision could be supported. You can find some useful information on the forum, as well as G1, due to project similarities.
WARNING: The DIR-825 series is prone to hardware failure of the Ethernet ports. There are numerous reports of this model developing problems with its LAN + WAN ports.

HW Rev CPU Ram Flash Network Gigabit USB Serial JTag
A1 Ubicom IP5170U@? 16MB ? 4×1 Yes Yes ? ?
B1/B2 Atheros AR7161@680MHz 64MB 8MB 4×1 Yes Yes Yes Yes
C1 Atheros AR9344@560MHz 128MB 16MB 4×1 Yes Yes Yes Yes
D1 Realtek RTL8197D@? 64MB 8MB 4×1 Yes Yes ? ?
E1 Realtek RTL8197DN@660MHz 64MB 8MB 4×1 Yes Yes Yes ?
G1 Realtek RTL8197DN@660MHz 64MB 8MB 4×1 Yes Yes Yes Yes

Note: More info about DIR-825 hardware revisions is available at Wikidevi (E1, G1, and more).

Consult flash.layout for a better understanding.

There are two ways of installing firmware, either by using normal D-Link firmware update web-interface or by using firmware recovery mode.

Note: Since original Firmware 2.05WW Build: 05Beta01 it is not possible to flash OpenWrt via the firmware update page. (worked on a B2 revision with Ubuntu's Firefox in 2.05NA and 2.06NA) It looks like Firmware 2.01EU behaves the same way. Please use the firmware recovery mode instead.

Note: This method works for revision B1 with Firmware 201EUB15, once the firmware identifier is fixed as follows: sed 's#00AP94-AR7161-RT#01AP94-AR7161-RT#' --in-place openwrt-XX.YY.Z-ar71xx-generic-dir-825-b1-squashfs-factory.bin. Use the following to get the firmware identifier: hexdump -C DIR825B1_FW201EUB15.bin | tail -3

00600000  30 31 41 50 39 34 2d 41  52 37 31 36 31 2d 52 54  |01AP94-AR7161-RT|
00600010  2d 30 38 30 36 31 39 2d  30 30                    |-080619-00|

Note: This method works for revision C2 with Firmware 3.00 using Ubuntu's Firefox. I used openwrt-ar71xx-generic-dir-825-c1-squashfs-factory.bin

  1. Login into the factory D-Link firmware web-interface as usual. Default procedure for the freshly purchased router is:
    1. Set the static IP on the PC
    2. With any web browser go to, use “admin” as the username, and “” as the password (leave the field blank).
  2. Proceed into the firmware update page, click “Browse” and select your OpenWrt image file (openwrt-ar71xx-generic-dir-825-b1-squashfs-factory.bin)
  3. Click “Update” and let the router reflash itself.
  4. Device should now reboot itself and boot up the OpenWrt.
  5. Give the router some time to finish firstboot tasks (initial configuration, jffs2 initialization, e.t.c.).
  6. The router's power LED should blink orange during bootup, as soon as it stops flashing, you can connect to it
  7. Obtain new IP from the router via DHCP and follow walkthrough_login

Phase 1: OS specific quirks

Note: The firmware recovery mode has following quirks:

  • If you have a Windows machine available you can use Microsoft Internet Explorer 7 (a Windows running on a VM, like VMware, does not work)
    • Windows 8: Firefox cannot be used to update firmware (presumably applies to other versions of Windows).
    • Windows 8: Use Internet Explorer 10. Press F12. Select Browser Mode: IE8. Leave the compatibility setting at IE5 Quirks.
    • Windows 7: try to turn off ipv6
    • Windwos 10: works with Netscape Navigator V9.0.0.6
  • If you are running Linux you can:
    • Ideally use C program below, otherwise:
    • Set your interface to 100Mbps using sudo ethtool -s eth0 speed 100 autoneg off, install IE7 in Wine and use it to flash.
    • Later models (or some hardware combinations) may need sudo ethtool -s eth0 speed 100 duplex half autoneg off (e.g. B2, FW ver 2.05EU).
    • firmware 2.02EU should still be available on ftp.dlink.de and it doesn't require IE, nor Mac.
    • 2.05EUB09_7 can't be downgraded to 2.04 but fortunately can be downgraded to 2.02EU
    • I had to disable both avahi, cups and IPv6 to get it working. (B2 FW ver 2.01EU)
  • If you are running MacOS you can use Google Chrome Opera
  • FW version 2.05EU seems very difficult to flash, there may be timing issues (that's just a guess). After downgrading to 2.04EU (get it from ftp.dlink.de) it worked the first time, using IE7 on a virtualbox Win XP “guest”. YMMV.
  • Rarely, some (ISP-Branded?) Routers lock out firmware updates in the recovery mode. This the case for DI-825s provided by Videotron, for example. If you get “firmware update failed” you may have to open the .bin file and modify the last bit from 00 to 01 or 02 with a Hex editor. More details: https://blog.incloudus.com/2013/flasher-un-routeur-d-link-dir-825-de-chez-videotron/

Phase 2: General steps

  1. Get into the D-Link recovery console with the steps below:
    1. While powering up the router, press and hold the reset button until the power LED starts blinking orange (usually takes around 45 (forty-five) seconds )
    2. Set a static IP on your PC to
    3. connect to, mind the quirks!
  2. Click “Browse” and select your OpenWrt image file (openwrt-ar71xx-dir-825-b1-squashfs-factory.bin, this binary image is available in the Backfire 10.03.1rc1 download directory and above)
  3. Click “Update” and let router flash the image (don't worry if it reboots before it reaches 100%). The page should display “Device is Upgrading the Firmware” in blue letters with the current percentage in red (with an incompatible Browser it doesn't). Look at the screenshot at the end of this section.
  4. The router's power LED should blink orange during bootup, as soon as it stops flashing, you can connect to it
  5. Tip! Note that default DHCP will allocate on 192.168.1.x, which is different subnet to the address you allocated above. This is why you can't connect until you change your IP address.
  6. obtain new IP from the router via DHCP and follow walkthrough_login

D-Link DIR-825 B2 after clicking "Update" in Firmware Recovery Mode, using IE7 on Wine in Linux

OEM Flash Layout

First, for familiarity you can look at the concept of flash.layout. It is also recommended that you know flash layout of DIR-825 before generic.sysupgrade, generic.backup, generic.debrick or failsafe_and_factory_reset.

D-Link DIR-825 Rev B Flash Layout
Layer0 m25p80 spi0.0: S25SL064A 8192KiB
Layer1 mtd0 u-boot 256KiB mtd1 config 64KiB mtd7 firmware 6208KiB mtd5 caldata 64KiB mtd6 unknown 1600KiB
Layer2 mtd2 kernel 1024KiB mtd3 rootfs 5184KiB mtd8 caldata_copy 64KiB
mountpoint /
filesystem overlayfs
Layer3 mtd4 rootfs_data 3328KiB
Size in KiB 256KiB 64KiB 1024KiB 1856KiB 3328KiB 64KiB 1536KiB 64KiB
Name u-boot config kernel rootfs_data caldata caldata_copy
mountpoint none none none /rom /overlay none none none
filesystem none none none SquashFS JFFS2 none none none

*Note* The partitions “mtd1 config”, “mtd5 caldata”, “mtd6 unknown” and “mtd8 caldata_copy” contain vendor specific raw (without filesystem) config values about your router, like WiFi calibration data, MAC addresses, etc. It's a good idea to make a backup from them. Similarly, “mtd0 u-boot” has some specific codes for DIR-825 (e.g. its “firmware recovery mode”); So you can backup that partition too.

*Note2* You can check mtd partitions of your router yourself by using commands “cat /proc/mtd” and “dmesg”. Refer to this link.

OpenWRT Flash Layout

This is the layout as is when OpenWRT 22.03.5 is installed.

D-Link DIR-825 Rev B Flash Layout
Layer0 m25p80 spi0.0: S25SL064A 8192KiB
Layer1 mtd0 u-boot 256KiB mtd1 config 64KiB mtd2 fwconcat0 6208KiB mtd3 caldata 64KiB mtd4 fwconcat1 1600KiB
Layer1 boundaries 0-0x040000 0x040000-0x050000 0x050000-0x660000 0x660000-0x670000 0x670000-0x800000
Layer2 mtd5 virtual_flash firmware 7808KiB (mtd3 is not included in the mtd5 concatenation*)
Layer2 boundaries Virtual: 0-0x7a0000 :0-0x610000 (from mtd2) + 0x610000-0x7a0000 (from mtd4)
Layer3 mtd6 kernel 2240KiB mtd7 rootfs 5568KiB
Layer3 boundaries Virtual: 0-0x230000 Real: 0x050000-0x280000 Virtual: 0x230000-0x7a0000 Real: 0x280000-0x660000 (from mtd2) + 0x670000-0x80000 (from mtd4)
mountpoint /
filesystem OverlayFS
Layer4 Un-named, 1 squashfs-split partition found as mtd8 mtd3 caldata 64KiB (likely!) mtd8 rootfs_data 1856KiB
Layer4 boundaries Virtual: 0x230000-0x5d0000 Real:0x280000-0x620000 0x660000-0x670000 Virtual: 0x5d0000-0x7a0000 Real: 0x620000-0x660000 (from mtd2) + 0x670000-0x800000 (from mtd4)
Size 256KiB 64KiB 2240KiB 3712KiB 64KiB 1856KiB
Name u-boot config kernel unknown unknown rootfs_data
mountpoint none none none /rom unknown /overlay
filesystem none none none SquashFS none JFFS2

FIXME (*) Unfold for explanations. Complete missing parts.

Click to display ⇲

Click to hide ⇱

dmesg from around boot time:

[ 0.762030] spi-nor spi0.0: m25p64 (8192 Kbytes)

[ 0.766707] 5 fixed-partitions partitions found on MTD device spi0.0

[ 0.773111] Creating 5 MTD partitions on “spi0.0”:

[ 0.777912] 0x000000000000-0x000000040000 : “u-boot”

[ 0.786178] 0x000000040000-0x000000050000 : “config”

[ 0.792153] 0x000000050000-0x000000660000 : “fwconcat0”

[ 0.799856] 0x000000660000-0x000000670000 : “caldata”

[ 0.805848] 0x000000670000-0x000000800000 : “fwconcat1”

[ 0.815426] Concatenating MTD devices:

[ 0.819255] (0): “fwconcat0”

[ 0.822128] (1): “fwconcat1”

[ 0.824994] into device “virtual_flash”

[ 0.828868] 1 fixed-partitions partitions found on MTD device virtual_flash

[ 0.836070] Creating 1 MTD partitions on “virtual_flash”:

[ 0.841507] 0x000000000000-0x0000007a0000 : “firmware”

[ 0.852505] 2 uimage-fw partitions found on MTD device firmware

[ 0.858482] Creating 2 MTD partitions on “firmware”:

[ 0.863440] 0x000000000000-0x000000230000 : “kernel”

[ 0.869392] 0x000000230000-0x0000007a0000 : “rootfs”

[ 0.876577] mtd: setting mtd7 (rootfs) as root device

[ 0.881833] 1 squashfs-split partitions found on MTD device rootfs

[ 0.888039] 0x0000005d0000-0x0000007a0000 : “rootfs_data”

<br> One can see that caldata cuts the firmware partition into two halves. The start and end addresses are the absolute one at Level1 (u-boot, config, fwconcat0, caldata, fwconcat1).<br>

From Level2 on, the reported addresses are relative. The table above lists both relative addresses and how they translate to absolute (“real”) ones.<br>

In the following, all mtd partitions ever present are listed.

root@DIR-825B1:~# cat /proc/mtd


Synthesis from the above:



:!: Make sure to read Upgrade from ar71xx to ath79 before upgrading from ar71xx to ath79!

Since this part is identical for all devices, see Basic configuration.

wireless.overview This router requires the packages kmod-ath9k and wpad-mini.

Architecture MIPS
Vendor Qualcomm Atheros
bootloader U-Boot
System-On-Chip AR7161 rev 2 (MIPS 24Kc V7.4)
CPU/Speed 24Kc V7.4 680 MHz
Flash-Chip Spansion S25FL064A
Flash size 8192 KiB
RAM 64 MiB
Wireless 2 x Atheros AR922X 2.4GHz/5.0GHz 802.11abgn
Ethernet RealTek RTL8366S Gigabit w/ port based vlan support
Internet n/a
USB Yes 2 x 2.0 (Only 1 header to the outside)
Serial Yes /dev/ttyS0


D-Link DIR-825 with the bottom cover removed


D-Link DIR-825 with bridges soldered to enable second USB port D-Link DIR-825 B2 with second USB port in use DIR-825 B2 2nd USB Wires Order


D-Link DIR-825 C1 board D-Link DIR-825 C1 Atheros chipset D-Link DIR-825 C1 RAM chips

Note: This may void your warranty!

To remove the cover simply:

  1. Remove the two (2) back rubber feet. (closest to the ethernet ports and antennas)
  2. Unscrew the two (2) screws underneath the feet.
  3. Pry case halves apart from back side to front side, carefully.

To remove the board from the casing:

  1. Unscrew the two (2) front (inner) screws and remove the LED shield.
  2. Lift board from front and slide out in a forward motion.

Remember to use 12V3.3V serial port voltage converter or you might break the router by over-voltage.

COM port settings: Speed:115200, Data bits:8, Stop bits:1, Parity:none, Flow control:none

How to connect to JTAG interface, and how to reflash the device with JTAG tools

See port.jtag for more JTAG details.

See the LED section in /etc/config/system on general LED configuration.

The DIR-825 has 11 blue and 2 orange LEDs: The four LAN LEDs are controlled by the switch chip. By default they show link and blink for activity. They are LED Bank 0. To configure the RealTek RTL8366S, you can use swconfig, e.g.

swconfig dev rtl8366s port 0 set led 2
LED name LED symbol Internal name blue Internal name orange
unknown D-Link unknown n/a
Power Power dir825b1:blue:power dir825b1:orange:power
Planet Planet dir825b1:blue:planet dir825b1:orange:planet
Wireless LAN 2.4 GHz Waves (2.4GHz) ath9k-phy0::phy0tpt n/a
Wireless LAN 5 GHz Waves (5GHz) ath9k-phy1::phy0tpt n/a
LAN Port 1 PC (1) n/a n/a
LAN Port 2 PC (2) n/a n/a
LAN Port 3 PC (3) n/a n/a
LAN Port 4 PC (4) n/a n/a
Universal Serial Bus USB dir825b1:blue:usb n/a
WPS Two arrows dir825b1:blue:powersave n/a

Repair LEDs after flashing OpenWrt

If you want to see the BLUE POWER ON and the BLUE GLOBE ( planet ) blinking when it receives information, then do the following setup:

For UCI configuration of the LEDs use this set of commands:

uci set system.led_wan_orange=led
uci set system.led_wan_orange.sysfs=d-link:orange:planet
uci set system.led_wan_orange.default=1
uci set system.led_wan_blue=led
uci set system.led_wan_blue.default=1
uci set system.led_wan_blue.sysfs=d-link:blue:planet
uci set system.led_wan_blue.trigger=netdev
uci set system.led_wan_blue.dev=eth1
uci set system.led_wan_blue.mode=link tx rx
uci set system.led_power_orange=led
uci set system.led_power_orange.sysfs=d-link:orange:power
uci set system.led_power_orange.default=0
uci set system.led_power_blue=led
uci set system.led_power_blue.sysfs=d-link:blue:power
uci set system.led_power_blue.default=1
uci commit system

After rebooting the device this setup becomes active.


The D-Link DIR-825 has two buttons:

Reset reset
WPS powersave

The WPS (WiFi Protected Setup) button is located at the right side (or the top when standing) and can be easily pressed with a finger. Also the WPS LED is integrated into the Button. For some unknown reason this control is named powersave in various places.

The Reset button is located at the back and cannot be pressed with a finger, you need a small item to push it in.

Numbers 0-3 are Ports 4 to 1 as labeled on the unit, 5 is the internal connection to the router itself.

Port Switch port
CPU (eth0) 5
No port 4
LAN 1 3
LAN 2 2
LAN 3 1
LAN 4 0

It was reported that in order to enable second USB port it is sufficient to solder in two straight bridges in place of L66 (take a look to the corresponding photo in the “Photos” section). After that you will need to solder in second USB header or - easier way - to solder in short-tailed female USB type A connector (sample photo is also available in the “Photos” section).

In the stock firmware, after you have soldered the bridges and USB head, if you connect a USB device (e.g. a USB Flash Drive) to the second USB head, the USB LED will turn blue.

Discussion and more information can be found in this thread.

vavasik did this mod and reported his experiences in this thread.

He used two Samsung K4H511638D-UCB3 chips from Samsung DDR SODIMM 512 MB. Maybe other chips from other manufacturers can be used, only they has to have 32Mx16 organization. Chips with other organization, such as 64Mx8, are not suitable.

Next to the soldering, the bootloader (U-Boot) and the calibration data partition has to be changed, because the D-Link bootloader/calibration data partition does not start with the 128 MB RAM. He used the bootloader/calibration data partition from Netgear WNDR3700. It's done through a full reflash, check the forum for the binary. It turn the D-Link DIR-825 into an Netgear WNDR3700.

The Netgear stock firmware does not recognize the 128 MB RAM, it only shows/uses 64 MB RAM, but it starts.

An detailed tutorial from vavasik can be found here.

Don't do this if your are inexperienced in soldering, you will for sure destroy the contacts→Trash!

D-Link DIR-825 B2 with 128 MB RAM Mod

Feel free to add here any info we haven't covered yet! Thank you!

I was able to upload the openwrt-ar71xx-generic-dir-825-b1-squashfs-factory.bin in recovery mode with Internet Explorer with compatibility view enabled (menu Tools/Compatibility View). Without it it was loading forever. Other browsers (Chrome, Firefox, Opera) were not working. Tested with Windows and Linux. Also I switched my 1Gbit cart into 100Mbit mode.

It may be necessary to run the original firmware and configure the device at least once. I flashed the router right away using the firmware recovery interface which resulted in configuration problems in OpenWrt. All wireless network devices did not have valid MACs instead they used 00:00:00:00:00:00 and refused therefore to work properly. Even trying to read the MAC from the sysfs failed. After flashing the original firmware and configuring the device once using the D-Link Webinterface everything worked as expected after flashing OpenWrt again.

Besides flashing in recovery mode from a MacBook Pro using Google Chrome and the default Gigabit plug worked just fine!

I had installed the openwrt-ar71xx-generic-dir-825-b1-squashfs-factory.bin using a Ubuntu system with Chrome using the original firmware update page in a DI-825 Rev B1 with FW 2.07NA

What is VLAN?

Read about VLAN

Situation - 6 global IPs from the ISP

  • Gateway:
  • SN-Mask:
  • ISP IPs: -
  • Router Model: D-Link DIR-825 rev. B1
  • Firmware Version: OpenWrt Backfire 10.03.1 / LuCI 0.10.0 Release (0.10.0)
  • Kernel Version:

What is the aim ?

Separate the LAN-Switch in such a manner, so that you can use the 4th LAN-Port as a global Port for the 6 given IPs from your ISP.

 D-825 Router with OpenWrt
 | LAN1 | LAN2 | LAN3 |   LAN4   |
 |                    |    |     
 |  your local LAN    |  Switch Netgear ProSafe 5
 |      |    |
 |                    |  global ips from your ISP
 |____________________|_ -

o) Go to Network / Switch and do the configuration as shown:

Separating the LAN1 + LAN2 + LAN3 from the LAN4

Very important is to hit the SAVE button ( !!! not the Save & Apply !!!)

In case if you wonder why the port 0 (zero) corresponds to the 4th LAN-port, see this: switch_ports

o) Go to Network / Interfaces / LAN / Physical Settings and do the following:

You have to change the settings from “eth0” to “eth0.1”

Now you should hit the button “Save & Apply” !!!

( Info: wait a bit and then you will see that your router is not responding any more → this is normal, give it a little time ( 1min max) then unplug the power supply from the router, then wait 10sec and plug it back in! )

o) Go to Network / Interfaces

You will find here only the LAN (green) and WAN (red) interfaces. Now we will have to add the VLAN-Interface ( I called it GLAN, you can call it GAN - it doesn't matter) - the G because of the global IPs!

o) Adding the GLAN Interface

a) Add new interfaces

b) Type in the name for the new interface: GLAN ( this is in my case, u can call it whatever u want)

c) Protocal of the new interface: Static address

d) Create a bridge over multiple interfaces: NO

e) Cover the following interface: VLAN Interface: “eth0.2”

f) Hit the Submit button

GLAN configuration overview:

This is what you will see, when you click the Interfaces

This is what you should see, after you added the GLAN Interface

To be sure that you have the right settings, check the /etc/config/network output:

root@dir825:~# cat /etc/config/network

config 'interface' 'loopback'
        option 'ifname' 'lo'
        option 'proto' 'static'
        option 'ipaddr' ''
        option 'netmask' ''

config 'interface' 'lan'
        option 'proto' 'static'
        option 'ipaddr' ''
        option 'netmask' ''
        option '_orig_ifname' 'eth0'
        option '_orig_bridge' 'true'
        option 'type' 'bridge'
        option 'ifname' 'eth0.1'

config 'interface' 'wan'
        option 'ifname' 'eth1'
        option 'proto' 'dhcp'

config 'switch'
        option 'name' 'rtl8366s'
        option 'reset' '1'
        option 'enable_vlan' '1'
        option 'enable_vlan4k' '1'

config 'switch_vlan'
        option 'device' 'rtl8366s'
        option 'vlan' '1'
        option 'ports' '1 2 3 5t'

config 'switch_vlan'
        option 'device' 'rtl8366s'
        option 'vlan' '2'
        option 'ports' '0 5t'

config 'interface' 'GLAN'
        option 'proto' 'static'
        option 'ifname' 'eth0.2'
        option 'ipaddr' ''
        option 'netmask' ''

o) Go to Network / Firewall and add a new GLAN-Zone:

a) name: GLAN

b) Input: accept

c) Output: accept

d) Forward: accept

e) Masquerading: YES

f) MSS clamping: YES

g) Covered networks: GLAN

h) Hit the Save & Apply button

o) Then check if GLAN is assigned to the correct firwall zone:

o) Go To Network / Firewall / Custom Rules and add the following lines (be aware to make changes for your own IPs | also the names of the variable can be changed)

# This file is interpreted as shell script.
# Put your custom iptables rules here, they will
# be executed with each firewall (re-)start.

### Variables ###

# public ip

# gets the wan-ip address
WANIP=`nvram get wan_ipaddr`

# disable NAT for FTP -> WAN
iptables -t nat -I POSTROUTING -s $PUBLIC -j ACCEPT

# allow traffic to routed public net
iptables -I FORWARD -o eth0.2 -j ACCEPT

# block public -> lan, allow lan -> public
iptables -I FORWARD -i eth0.2 -o br0 -m state --state NEW -j DROP

# block access to the router GUI/telnet/DNS/etc. from PUBLIC net, allow from HOSTS
iptables -I INPUT -i eth0.2 -j DROP
iptables -I INPUT -s $FTP -j ACCEPT
iptables -I INPUT -s $DNS1 -j ACCEPT
iptables -I INPUT -s $DNS2 -j ACCEPT
iptables -I INPUT -s $MAIL -j ACCEPT
iptables -I INPUT -s $BACKUP -j ACCEPT

# block access to WAN IP from PUBLIC net
iptables -I INPUT -i eth0.2 -d $WANIP -j DROP

Now hit the Save & Apply button

This are the settings of your machine (ex. FTP):


!!! Be aware to turn ON a firewall, because now the machine is exposed to the public !!!

The following program allows you to flash the DIR-825 from Linux without need of a VM with Windows with IE6.

The DIR-825 requires some rather peculiar TCP settings, and relies on some broken IE6 behaviour, which is why flashing with Firefox on Linux (or Firefox on Windows) doesn't work. The ruby script on the next section does *NOT* always work for this reason (perhaps due to different versions of ruby or underlying OS having different defaults).

I therefore have hacked on (it's not nearly my best work) a basic 'C' program that flashes the DIR-825 (and probably DIR-600/601 as well). It uses the HTTP headers as IE6 and uses the required TCP settings under Linux.

To use this program save as dlinkflash.c and do

gcc -o dlinkflash dlinkflash.c

Then copy dlinkflash to some location in your PATH, or do ./dlinkflash <firmware-filenname>

/* dlinkflash - Tool flash older d-link routers via emergency web interface
 * You must have 192.168.0.x/24 (where X=2-254) IP address on the
 * interface connected to the d-link and use the emergency flashing interface
 * Copyright 2014 Daniel Dickinson
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <regex.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
void build_post_bin(uint8_t **post, size_t *post_len, uint8_t *newdata, size_t datalen) {
    uint8_t *newpost = NULL;
    newpost = malloc((*post_len + datalen) * sizeof(uint8_t));
    if (*post) {
	memcpy(newpost, *post, *post_len);
    } else {
        *post_len = 0;
    memcpy(newpost + *post_len, newdata, datalen);
    *post_len += datalen;    
    if (*post)
    *post = newpost;
void build_post(uint8_t **post, size_t *post_len, char *newchar, size_t *content_len) {
    uint8_t *newpost = NULL;
    size_t nlen;
    build_post_bin(post, post_len, newchar, strlen(newchar));
    if (content_len) {
        *content_len += strlen(newchar);
void usage(char *exename) {
    printf("Usage: %s <filename> [-d]\n", exename);
    printf("   Interface attached to d-link must have IP addres 192.168.0.x/24 where x != 1\n");
int open_socket(void) {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    unsigned int tcpflush = 1;
    unsigned int recvbufsz = 512;
    unsigned int smallwindow = 512;
    unsigned int mss = 1024;
    setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &recvbufsz, sizeof(recvbufsz));
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &recvbufsz, sizeof(recvbufsz));
    setsockopt(sock, IPPROTO_IP, TCP_NODELAY, &tcpflush, sizeof(tcpflush));
    setsockopt(sock, IPPROTO_IP, TCP_MAXSEG, &mss, sizeof(mss));
    setsockopt(sock, IPPROTO_IP, TCP_WINDOW_CLAMP, &smallwindow, sizeof(smallwindow));
    struct sockaddr_in ipaddr;
    in_addr_t hostip = inet_addr("");
    ipaddr.sin_family = AF_INET;
    ipaddr.sin_port = htons(80);
    ipaddr.sin_addr.s_addr = hostip;
    if (connect(sock, (struct sockaddr *)&ipaddr, sizeof(struct sockaddr)) < 0) {
        return -1;
    return sock;
void send_get(int *sock, uint8_t *get, size_t getlen, uint8_t *post, int debug) {
    size_t socksent = 0;
    size_t curpos = 0;
    *sock = open_socket();
    if (*sock < 0) {
        if (post)
    while (curpos < getlen) {
        if ((getlen - curpos) >= 512) {
	    socksent = send(*sock, get + curpos, 512, 0);
            if (debug)
                fprintf(stderr, "Sent %d bytes\n", socksent);
	    if (socksent < 0) {
                if (post)
	} else {
	    socksent = send(*sock, get + curpos, getlen - curpos, 0);
            if (debug)
                fprintf(stderr, "Sent %d bytes\n", socksent);
	    if (socksent < 0) {
                if (post)
        curpos += socksent;
        printf("\r%d/%d Bytes written: GET %g%% complete                          ", curpos, getlen, ((float)curpos / (float)getlen) * (float)100);
    printf("\nFinished sending GET. Waiting for response.\n");
int main(int argc, char *argv[]) {
    uint8_t *firmware = NULL;   
    uint8_t *post = NULL;
    size_t postlen = 0;
    uint8_t *get = NULL;
    size_t getlen = 0;
    uint8_t *content = NULL;
    size_t contentlen = 0;
    size_t nonnllen = 0;
    size_t firmwarelen = 0;
    char contentlenstr[1024];
    size_t curpos = 0;
    contentlenstr[0] = 0;
    int debug = 0;
    if (argc < 2) {
   if (argc == 3) {
        if (!strncmp(argv[2], "-d", 2)) {
	    debug = 1;
        } else {
    } else if (argc > 2) {
    printf("Load firmware file %s\n", argv[1]);
    int firmwarefd = open(argv[1], 0);
    if (firmwarefd < 0) {
    size_t len = 0;
    uint8_t buf[1024];
    uint8_t *newfw = NULL;
    int sock;
    do {
        len = read(firmwarefd, &buf[0], 1024);
        if (len < 0) {
        if (firmware)
        if (len > 0) {
	    newfw = malloc((firmwarelen + len) * sizeof(uint8_t));
	    if (firmware)
		memcpy(newfw, firmware, firmwarelen);
	    memcpy(newfw + firmwarelen, &buf[0], len);
	    firmwarelen += len;
	    if (firmware)
	    firmware = newfw;
    } while (len > 0);
    printf("Firmware %u bytes long\n", firmwarelen);
    build_post(&content, &contentlen, "---------------------------7de1fe13304\r\n", NULL);    
    nonnllen += 2;
    build_post(&content, &contentlen, "Content-Disposition: form-data; name=\"files\"; filename=\"C:\\My Documents\\firmware.bin\"\r\n", &nonnllen);
    build_post(&content, &contentlen, "Content-Type: application/octet-stream\r\n", &nonnllen);
    build_post(&content, &contentlen, "\r\n", &nonnllen);
    build_post_bin(&content, &contentlen, firmware, firmwarelen);
    build_post(&content, &contentlen, "\r\n---------------------------7de1fe13304--\r\n", NULL);
    nonnllen += 4;
    /* IE6 off-by-one content-length error? */
    sprintf(contentlenstr, "%d\r\n", nonnllen + firmwarelen + 1);
    build_post(&get, &getlen, "GET / HTTP/1.1\r\n", NULL);
    build_post(&get, &getlen, "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n", NULL);
    build_post(&get, &getlen, "Accept-Language: en-ca\r\n", NULL);
    build_post(&get, &getlen, "Accept-Encoding: gzip, deflate\r\n", NULL);
    build_post(&get, &getlen, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322)\r\n", NULL);
    build_post(&get, &getlen, "Host:\r\n", NULL);
    build_post(&get, &getlen, "Connection: Keep-Alive\r\n", NULL);
    build_post(&get, &getlen, "\r\n", NULL);
    build_post(&post, &postlen, "POST /cgi/index HTTP/1.1\r\n", NULL);
    build_post(&post, &postlen, "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n", NULL);
    build_post(&post, &postlen, "Referer:\r\n", NULL);
    build_post(&post, &postlen, "Accept-Language: en-ca\r\n", NULL);
    build_post(&post, &postlen, "Content-Type: multipart/form-data; boundary=---------------------------7de1fe13304\r\n", NULL);
    build_post(&post, &postlen, "Accept-Encoding: gzip, deflate\r\n", NULL);
    build_post(&post, &postlen, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322)\r\n", NULL);
    build_post(&post, &postlen, "Host:\r\n", NULL);
    build_post(&post, &postlen, "Content-Length: ", NULL);
    build_post(&post, &postlen, contentlenstr, NULL);
    build_post(&post, &postlen, "Connection: Keep-Alive\r\n", NULL);
    build_post(&post, &postlen, "Cache-Control: no-cache\r\n", NULL);
    build_post(&post, &postlen, "\r\n", NULL);
    build_post_bin(&post, &postlen, content, contentlen);
    printf("Initiating GET so that router is in state to receive POST....");
    send_get(&sock, get, getlen, post, debug);
    int gotlen = 0;
    char recvbuf[1024];
    int recvlen = recv(sock, &recvbuf[0], 512, MSG_WAITALL);
    int newrecvlen;
    if (debug)
        fprintf(stderr, "Got %d bytes\n", recvlen);
    if (debug) {
        fprintf(stderr, "%s", &recvbuf[0]);
    do {
       if (recvlen < 0) {
       if (recvlen > 0) {
          recvlen = recv(sock, &recvbuf[0], 512, MSG_WAITALL);
          if (debug) {
 	      fprintf(stderr, "Got %d bytes data\n", recvlen);
              if (recvlen > 0) 
                  fprintf(stderr, "%s", &recvbuf[0]);
    } while (recvlen > 0);
    printf("Got page from which upload is done.\n");
    shutdown(sock, SHUT_RDWR);
    printf("Initiating transfer....");
    sock = open_socket();
    if (sock < 0) {
    size_t socksent = 0;
    curpos = 0;
    while (curpos < postlen) {
        if ((postlen - curpos) >= 512) {
	    socksent = send(sock, post + curpos, 512, 0);
            if (debug)
                fprintf(stderr, "Sent %d bytes\n", socksent);
	    if (socksent < 0) {
	} else {
	    socksent = send(sock, post + curpos, postlen - curpos, 0);
            if (debug)
                fprintf(stderr, "Sent %d bytes\n", socksent);
	    if (socksent < 0) {
        curpos += socksent;
        printf("\r%d/%d Bytes written: Upload %g%% complete        ", curpos, postlen, ((float)curpos / (float)postlen) * (float)100);
    printf("\nFinished sending post. Waiting for response.\n");
    regex_t pattern;
    if (regcomp(&pattern, "count_down", REG_NOSUB)) {
	printf("Error compiling expression to detect success or failure\n");
    recvbuf[0] = 0;
    recvlen = recv(sock, &recvbuf[0], 512, MSG_WAITALL);
    if (debug) {
        fprintf(stderr, "Got %d bytes\n", recvlen);
        fprintf(stderr, "%s", &recvbuf[0]);
    int firstpacket = 1;
    do {
       if (recvlen < 0) {
       } else if (recvlen > 0) {
           if (!regexec(&pattern, &recvbuf[0], 0, NULL, 0)) {
              printf("Firmware successfully sent.  Please wait for device to reboot.\n");
              if (firstpacket) {
	          printf("Error sending firmware to device.  Response is:\n");
	      printf("%s", &recvbuf[0]);
          recvlen = recv(sock, &recvbuf[0], 512, MSG_WAITALL);
          if (debug) {
 	      fprintf(stderr, "Got %d data\n", newrecvlen);
              if (recvlen > 0)
                 fprintf(stderr, "%s", &recvbuf[0]);
       firstpacket = 0;
    } while (recvlen > 0);
    shutdown(sock, SHUT_RDWR);
    return 0;    

*NB*: The ruby script on the next section does *NOT* always work for the reasons mentioned above (perhaps due to different versions of ruby or underlying OS having different defaults).

We have recently developed a script and performed some correction based on your work you can find it here

You need to have ruby installed.

Script recovered from the WayBackMachine: https://web.archive.org/web/20120418003158/http://openwisp.caspur.it/wiki/owf/FlashingDlinkDIR825#notextile-Automatic-flashing-script-notextile

With this script it's not necessary to force your NIC to work @ 10/100 Mb/s and it's not necessary using IE7

# Copyright (C) 2011 CASPUR (wifi@caspur.it)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# This script will help you flashing D-LINK DIR-825 devices 'cause  they can be flashed only with IE7
# Your ETH Address must be
require 'socket'
HOST = "" 
PATH = "/cgi/index" 
if ARGV.count == 0
  puts "Usage #{$0} <filename>" 
  exit 1
  filename = ARGV[0]
  puts "[#{Time.now}] Using firmware file '#{filename}'" 
predata = <<-eopd
Content-Disposition: form-data; name="files"; filename="#{filename}" 
Content-Type: application/octet-stream
firmware = File.open(filename, "rb") { |io| io.read }
# Each line must end with cr/lf characters, and we have to know how many 
# data the script will send to the dir-825 this is why we concatenate it before
# creating the header
buffer = predata.gsub(/\n/,"\x0d\x0a") + firmware + postdata
header = <<-eoh
Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, */*
Referer: http://#{HOST}/
Accept-Language: it-IT
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
Content-Type: multipart/form-data; boundary=---------------------------7db12928202b8
Accept-Encoding: gzip, deflate
Host: #{HOST}
Content-Length: #{buffer.length}
Connection: Keep-Alive
Cache-Control: no-cache
  puts "[#{Time.now}] Firmware file laded (#{firmware.length} bytes)" 
  http = TCPSocket.new(HOST, 'www')
  puts "[#{Time.now}] Sending firmware to the device...  " 
  http.print header.gsub(/\n/,"\x0d\x0a") + buffer
  resp = http.recv(1012)
  # Let's check if it's all ok
  if resp.match /Don't turn the device off before the Upgrade jobs done/
     puts "\n[#{Time.now}] Finished. Please wait for the device to reboot." 
     puts "\n[#{Time.now}] Problem sending firmware to the device. Response from device follows." 
     puts resp
  rescue Exception => e
  puts "[#{Time.now}] Problem flashing device. Error: '#{e}'" 
exit 0

Since Attitude Adjustment beta 2, some images are suffixed with “-fat” to indicate they will be able to use more flash that the factory firmware uses by default. It does this by moving the wireless interface calibration data at the end of the flash. This is a dangerous operation and should only be performed if you know how to back this flash partition (/dev/mtd5). To upgrade, you'll need to copy the whole image in /tmp and use sysupgrade -i the caldata question. Downgrading to a non-fat image will get the caldata back in place so it can be used by the factory firmware, after upgrading to a fat image, you must downgrade before getting back to a factory image.

Before: /dev/mtdblock4 576.0K 308.0K 268.0K 53% /overlay After: /dev/mtdblock4 2.1M 328.0K 1.8M 15% /overlay

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2024/07/14 04:06
  • by cubytus