Tuesday, June 29, 2010

Asterisk, the VoIP Server on DD-WRT

I'm a big fan of Asterisk on router -- imho, it's the perfect platform for anyone want to try Asterisk at home -- 24x7, fanless and even the cheapest router can handle at least 2-3 concurrent conversation. Before this WZR-HP-G300NH, I had Asterisk running on a WRT54G-TM for over a year with lots of fun.

Installing Asterisk on the router is easier now as current OpenWrt trunk build(the one we use) includes prebuilt Asterisk binaries. As always, since OpenWrt is designed to work with / not /opt, some adjustment is required to get Asterisk working properly.

  1. Install Asterisk 1.6
    Believe it or not, DD-WRT MEGA also has Asterisk included -- it's an old ver1.4 and some important files are missing -- I have no idea why DD-WRT decided to do so, too much flash ROM? Anyway, to install Asterisk 1.6 on our opkg enabled router, run
    opkg install asterisk16

    You may also want to install some additional modules like:
    opkg install asterisk16-res-agi
    opkg install asterisk16-res-musiconhold

    To view a full list of Asterisk packages(lots of them!), run
    opkg list | grep asterisk16

  2. The configuration file: asterisk.conf
    With our installation, the asterisk.conf is in /opt/etc/asterisk/asterisk.conf. Change it to the contents below:

    [directories] ; remove the (!) to enable this
    astetcdir => /opt/etc/asterisk
    astmoddir => /opt/usr/lib/asterisk/modules
    astvarlibdir => /opt/usr/lib/asterisk
    astdbdir => /opt/usr/lib/asterisk
    astkeydir => /opt/usr/lib/asterisk
    astdatadir => /opt/usr/lib/asterisk
    astagidir => /opt/usr/lib/asterisk/agi-bin
    astspooldir => /var/spool/asterisk
    astrundir => /var/run/asterisk
    astlogdir => /var/log/asterisk
  3. [compat]

    As you can see, by modifying this file, we tell Asterisk to look for files at /opt/etc/asterisk and /opt/usr/lib/asterisk instead of default locations, which fits our installation.

    Now try to launch asterisk by running:
    asterisk -vvvvvc
    Exit by pressing ctrl+c

  4. Asterisk configuration
    By default, asterisk loads lots of modules, you can change the settings to fit your needs and reduce memory usage.

    Below is a sample of /opt/etc/asterisk/modules.conf with reduced modules:

    autoload=no                ; only load explicitly declared modules
    load => app_dial.so
    load => app_echo.so
    load => app_macro.so
    load => app_playback.so
    load => chan_sip.so
    load => codec_ulaw.so
    load => pbx_config.so
    load => format_pcm.so
    load => format_wav.so
    load => func_callerid.so
    load => func_strings.so
    load => res_musiconhold.so
    load => res_agi.so

    For SIP users, other important files including /opt/etc/asterisk/extensions.conf and /opt/etc/asterisk/sip.conf. These are not covered here, please refer to website about Asterisk like asteriskguru and voip-info.org. Also, here is a must-read  ebook: Asterisk: The Future of Telephony Second Edition(download the PDF book)

  5. Run it as service
    Create file /opt/etc/init.d/asterisk with below(delete previous contents if its not empty)

    source /mnt/root/.profile
    mkdir -p /var/run/asterisk
    mkdir -p /var/spool/asterisk
    mkdir -p /var/log/asterisk/cdr-csv
    /opt/usr/sbin/asterisk -C /opt/etc/asterisk/asterisk.conf

    And run
    chmod a+x /opt/etc/init.d/asterisk
    ln -s /opt/etc/init.d/asterisk /opt/etc/init.d/S95asterisk

That's all. Enjoy Asterisk and happy VoIP!


Lighttpd and php on DD-WRT

Busybox httpd is good for simple static pages, now here is a tutorial for installing lighttpd and php with fastcgi support in the router. Here I choose lighttpd over Apache for its light cpu usage and small memory footprint.

Since all our software are based in /opt folder, some modification must be done to get everything working:

  1. Install php5 and lighttpd
    To install php5 with fastcgi support, run
    opkg install libsqlite3
    opkg install php5-fastcgi
    opkg install php5-modgd
    Along with php5, the popular libgd module is also installed. Copy php.ini to its default location.
    cp /opt/etc/php.ini /etc/php.ini

    After that, test php installation by running:
    php-cgi -v

    You should see the version info and no warning/error message.

    Install lighttpd and some modules
    opkg install lighttpd
    opkg install lighttpd-mod-fastcgi
    opkg install lighttpd-mod-simple-vhost

  2. Modify php.ini
    Edit /etc/php.ini
    Find doc_root = "/www"(or whatever) and change it to doc_root = "/opt/www"
    Find extension_dir = "/usr/lib/php" and change it to extension_dir = "/opt/usr/lib/php"
    Find ;extension=gd.so and remove the leading semicolon, i.e., change it to extension=gd.so
    Find ;date.timezone= , remove the leading semicolon and change it to
    date.timezone = "America/New_York"
    Replace the red part with yours, a full list is available here.

  3. Modify lighttpd.conf
    With our installation, the configuration file for lighttpd is located at /opt/etc/lighttpd/lighttpd.conf. Edit this file:

    First, enable mod_fastcgi and mod_simple_vhost:

    find server.document-root  and change its value to "/opt/www"

    find #server.port = 81 and change it to server.port = 81
    This will set lighttpd server to listen port 81. If you want to use port 80, make sure to move the DD-WRT's web admin to another port, details here, step 1.

    add following at the end of the file:

    fastcgi.server = ( ".php" => ((
                         "bin-path" => "/opt/usr/bin/php-cgi",
                         "socket" => "/tmp/php.socket"

  4. Lighttpd startup script
    Create or edit file /opt/etc/init.d/lighttpd with below. Remove any previous contents if its not empty.


    source /mnt/root/.profile



    [ $# -eq 0 ] && COND="start"

    case $COND in
      killall lighttpd
      killall php-cgi
      mkdir -p $LOG_D
      mkdir -p $RUN_D
      $BIN -f /opt/etc/lighttpd/lighttpd.conf -m /opt/usr/lib/lighttpd
      exit 1

    Set it as a service
    chmod a+x /opt/etc/init.d/lighttpd
    ln -s /opt/etc/init.d/lighttpd  /opt/etc/init.d/S80lighttpd

  5. Test lighttpd server
    First create the home folder
    mkdir /opt/www

    Then the test file /opt/www/phpinfo.php with contents below:


    After that, launch lighttpd
    #to stop the lighttpd server, run /opt/etc/init.d/lighttpd stop

    Open browser and navigate to http://router_ip:81/phpinfo.php to check the output.


Monday, June 28, 2010

Simple busybox http server on DD-WRT

By default DD-WRT runs its own http server(/usr/sbin/httpd), providing web management interface to configure the router. The server is highly integrated and hard to reuse for our own contents. If you just want to host some web pages without CGI support, the httpd server in busybox is a good alternative.

  1. (Optional)Move DD-WRT's web admin to another port
    The best way to do so is changing a nvram value as described here.
    So login the router and run
    nvram set http_lanport=88
    nvram commit

    Then after rebooting, the new port will be 88 and you can access the web admin at http://router_ip:88/. Everything should work just as before including firmware upgrade.

  2. Configure busybox httpd
    The OpenWrt's busybox is installed if you followed the previous post. This busybox provides more features than the DD-WRT one, including a small web server. To launch it, run
  3. /opt/usr/sbin/httpd -p 80 -c /opt/etc/httpd.conf -h /opt/www

    the server(/opt/usr/sbin/httpd) will listen port 80(-p 80) with configuration file /opt/etc/httpd.conf(-c /opt/etc/httpd.conf) and use /opt/www as home folder(-h /opt/www).

    Everything looks good, except, both our http server and dd-wrt's are called httpd. This will be a problem as DD-WRT will kill and restart the httpd service when applying some settings. If that ever happens, our httpd service will be terminated unexpectedly. So let's change the service name.

    Here is (another) dirty hack but works for me. Log in PuTTY and run:

    cp /opt/bin/busybox /opt/bin/busybox.orig
    cp /opt/bin/busybox /tmp/busybox
    sed -i 's/httpd$/httpe/g' /tmp/busybox
    cp /tmp/busybox /opt/bin/busybox
    ln -s /opt/bin/busybox /opt/usr/sbin/httpe

    So now we have changed the name of busybox's http server from httpd to httpe. If it's messed up, restore the old busybox:
    /bin/cp /opt/bin/busybox.orig /opt/bin/busybox

  4. Run it as service
    Create file /opt/etc/init.d/httpd

    source /mnt/root/.profile
    /opt/usr/sbin/httpe -p 80 -c /opt/etc/httpd.conf -h /opt/www

    And run
    chmod a+x /opt/etc/init.d/httpd
    ln -sf /opt/etc/init.d/httpd /opt/etc/init.d/S20httpd


Sunday, June 27, 2010

Upgrade DD-WRT and Keep Installed Applications

The DD-WRT support for these new 11N Gigabit routers are still in early stage with new builds rolling out every one to two weeks. The old good "if its not broken then don't fix it" rule might not apply here and I suggest to stay with latest release if you have the time(and guts).

Upgrading a DD-WRT firmware with loaded software is pretty easy, considering the extra work we've done. Take the trouble not to mess with important system folders like /lib /usr and /bin and now its the reward time.

  1. Stop installed software
    Log in the router, rename the /mnt/optware.enable
    mv /mnt/optware.enable /mnt/optware.disable

    Then reboot the router. After rebooting, the router is back to standard DD-WRT with no extra load and ready for flashing.

  2. Upgrade firmware
    Get the new DD-WRT build, the name should be wzr-hp-g300nh-dd-wrt-webupgrade-MULTI.bin. Some suggests a hard reset before and after upgrading but I usually just select "Reset to Default Settings" during flash.
    After flashing, all settings will be erased and then you have to start over again.

  3. Set the router
    Set the router as usual. Here is a quick list for additional setup, all are covered in other posts, I just put these together for easy reference.

    Enable SSH and USB Support. Details here, Step 2.
    Customized startup script. Details here, Step 10.
    Disable DD-WRT's NTP Client if you're about to use local time. Details here, Step 1.
    Disable built-in FTP server(should be off by default). Details here, Step 1.

    Then some nvram variables:

    #use local time. details here, step 3. Change it accordingly
    nvram set time_zone=PST8PDT,M3.2.0,M11.1.0
    move dd-wrt's web admin to another port. Details here, step 1
    nvram set http_lanport=88
    nvram commit

    After that, reboot the router.

  4. Update writable /etc and re-enable installed apps
    After reboot, login the router and run:

    cp -a /etc/* /mnt/etc/
    mv /mnt/optware.disable  /mnt/optware.enable

    The first line is very important. It's for synchronizing our the customized /etc folder with the new firmware's /etc folder. Forget to do so will break the web management interface!

    Somewhat modified, the files in /etc folder are only added(like /etc/TZ) or dynamically updated(the adduser script), so it's safe to overwrite the /etc folder with new contents and all our work is kept intact. After that, reboot the router, and you should have a new DD-WRT with all previously installed software running.

  5. Fix the broken web interface
    You'll get this error ONLY if you forget to update the /etc folder, see Step 4 above. If this ever happens:
    SSH or telnet login the router, run

    mv /mnt/optware.enable /mnt/optware.disable

    the web interface should be back after rebooting, then follow Step 4.

    If the web interface is messed and you can't login from PuTTY, unplug the USB disk and power cycle the router. Then manually mount the USB disk(details here, step 2 and 6) and update /etc folder following Step 4.


Workaround for Stuck Beacon Problem

Stuck beacon is a notorious problem on madwifi (the wireless driver DD-WRT used for Atheros routers).  If you never experienced any wireless interruptions with DD-WRT then just ignore this article. However, if you're annoyed by this stuck beacon problem with constantly dropping wireless connection, then I hope this can be of help.

I personally prefer the open source ath9k driver which doesn't suffer from this, but some important feature like WDS is missing from ath9k. So to each its own, DD-WRT has the perfect reason to stick with madwifi and I don't expect the switch to ath9k anytime soon. And, seems that the problem only happens under certain circumstance. In my case, the connection drops with an Atheros wireless N card -- same card works great with stock firmware -- but works fine with another Intel WiFI 1000 11N card. So if a stable wireless connection is very important, the best solution might be flashing back to stock firmware or just try another card.

Below is a quick hack, not a completely fix but would make life a little easier. The idea is to watch the output of dmesg and when the "stuck beacon" error messages flood, reset the wireless interface to bring it back to life.

  1. The watchdog script
    When wireless connection is dropeed, a typical out from dmesg would like this

    ath_bstuck_tasklet : Entering
    Resetting; Code: 01
    ath_bstuck_tasklet : Entering
    Resetting; Code: 01
    ath_bstuck_tasklet : Entering
    Resetting; Code: 01
    ath_bstuck_tasklet : Entering
    Resetting; Code: 01
    ath_bstuck_tasklet : Entering
    Resetting; Code: 01
    ath_bstuck_tasklet : Entering
    Resetting; Code: 01

    the same error message will keep repeating and flood the kernel log. So we can use this as a trigger and reset wireless interface when the error occurs.

    Below is the /opt/usr/local/bin/wifi-watchdog.sh script


    dmesg | tail -n 5 | grep -q ath_bstuck_tasklet || exit

    echo fixing...
    #a log file
    echo `date` >> /tmp/wifi-wathdog.log

    ifconfig ath0 down
    #for VAP, bring additional interface(s) down
    #ifconfig ath0.1 down
    sleep 2
    ifconfig ath0 up
    #bring it back
    #ifconfig ath0.1 up

    Set permissions
    chmod a+x /opt/usr/local/bin/wifi-watchdog.sh

  2. Set cron job
    With the watchdog script ready, we can use cron to set it run every one minute.
    Add a new job:

    * * * * * /opt/usr/local/bin/wifi-watchdog.sh

    and it's done. Again, its not a completely fix just save the trouble of resetting the router each time.


Wireless Scheduler with Cron Job

Cron is a time-based job scheduler in Linux systems which enables users to schedule jobs (commands or shell scripts) to run periodically at certain times or dates. In this example, we'll use cron to control the wireless signal, set it to turn on only at given time.

DD-WRT is shipped with cron support but again we'll use our own cron daemon as it's easier for future update and will save some flash wearing.

  1. Disable DD-WRT's Cron
    From the web interface, Administration->Management, find "Cron" and disable it, then click "Apply Settings"

  2. Install cron(busybox) service
    The cron is provided by busybox and should've been installed. If not, run
    opkg install busybox

    and create the scheduling file folder:
    mkdir /etc/crontabs

    Set it to run on startup by creating /opt/etc/init.d/crond with following:

    source /mnt/root/.profile
    kill -9 $(pidof crond)

    chmod a+x /opt/etc/init.d/crond
    ln -s /opt/etc/init.d/crond /opt/etc/init.d/S80crond

  3. The script to switch wireless
    Now create a file /opt/usr/sbin/wireless-off.sh

    /sbin/ifconfig ath0 down

    another one: /opt/usr/sbin/wireless-on.sh

    /sbin/ifconfig ath0 up

    On VAP enabled routers, additional interfaces like ath0.1, ath0.2...etc. also need to be taken care of:
    /sbin/ifconfig ath0.1 down
    /sbin/ifconfig ath0.1 up
    The full list of wireless interfaces can be found by running /sbin/ifconfig

    Don't forget the permission:
    chmod a+x /opt/usr/sbin/wireless-on.sh /opt/usr/sbin/wireless-off.sh

  4. Edit Cron Scheduler
    DD-WRT's wireless scheduling is available only for Broadcom routers(see picture below) but missing from Atheros builds.
    However, its not hard to implement this on Atheros routers with the help of cron and the scripts above.
    For example, to turn on wireless only from 5pm to 11pm, run
    crontab -e
    which will bring you the cron job editor. Add two lines like that

    0 17 * * *   /opt/usr/sbin/wireless-on.sh
    0 23,0-16 * * *   /opt/usr/sbin/wireless-off.sh

    Save. The wireless-on script will runs only once at 5PM(17:00) but the wireless-off script runs every hour(23:00, 0:00 ... 16:00) to ensure the wireless can still be turned off in case the router is rebooted halfway.

    Now how about turning off wireless only on weekdays?

    0 17 * * *   /opt/usr/sbin/wireless-on.sh
    0 23,0-16 * * 1-4   /opt/usr/sbin/wireless-off.sh
    0 0-16 * * 5   /opt/usr/sbin/wireless-off.sh

    Refer here for the full instruction about cron.


BitTorrent Client: Transmission on DD-WRT

If you've followed the previous guides to set the opkg system, then installing transmission on the USB enabled DD-WRT system is a no-brainer. Only one little thing needs to be taken care of...

  1. Install transmission
    To do so, Use PuTTY to log in and run the command below:
    opkg install transmission-web

    This will install libevent(required library) transmission-daemon(the actual program) and transmission-web(the web interface).

  2. Setup transmission
    wait for 10 seconds then stop it:
    killall transmission-daemon

    This will create default configuration file for transmission, the file is located at /mnt/root/.config/transmission-daemon/settings.json
    Edit this file with following(delete all previous contents)

    "blocklist-enabled": 1,
    "download-dir": "\/mnt\/share\/torrents",
    "download-limit": 100,
    "download-limit-enabled": 1,
    "encryption": 2,
    "max-peers-global": 35,
    "peer-port": 25000,
    "pex-enabled": 1,
    "port-forwarding-enabled": 1,
    "rpc-authentication-required": 0,
    "rpc-password": "",
    "rpc-port": 9091,
    "rpc-username": "",
    "rpc-whitelist": "192.168.1.*",
    "upload-limit": 200,
    "upload-limit-enabled": 1

    Above is taken from DD-WRT wiki with some modification. Also create the download folder
    mkdir -m 777 /mnt/share/torrents

    So now all configure files for transmission are in /mnt/root/.config(or /tmp/root/.config, its the same). Downloaded files will be in /mnt/share/torrents

  3. Set transmission for web access
    This is usually not a problem, however, in our setup, the web pages is are in non-standard location. So we must let transmission aware of the change.

    To do so, a variable must be set for transmission. Run the command lines below:
    export TRANSMISSION_WEB_HOME='/opt/usr/share/transmission/web/'

    Now access transmission web manage interface at http://ip_of_the_router:9091/
    If everything works out, move to next step.

  4. Run it as service
    To do so, add the following line to /mnt/root/.profile

    export TRANSMISSION_WEB_HOME='/opt/usr/share/transmission/web/'

    Then create the startup script /opt/etc/init.d/transmission(delete all previous contents if its not empty)

    source /mnt/root/.profile
    sleep 2
    transmission-daemon -g /mnt/root/.config/transmission-daemon/

    Set it to run as service:
    chmod a+x /opt/etc/init.d/transmission
    ln -s /opt/etc/init.d/transmission /opt/etc/init.d/S60transmission


Saturday, June 26, 2010

Advanced Printer Sharing with hotplug

Hotplug is a set of scripts running upon certain predefined conditions. On today's Linux system, hotplug can do many things from auto mounting USB drive, pairing bluetooth devices to network configuration.

Seldom mentioned, but DD-WRT does offer (very preliminary) hotplug support. With almost no info on the web, the job is done by digging though DD-WRT's source code and various Linux documents.

  1. Replace DD-WRT's event handler with our own
    By default, DD-WRT registers /sbin/hotplug to handle all hotplug requests but the program, /sbin/hotplug doesn't follow standard hotplug rules, and, per my understanding, is a dummy and does nothing at all. So let's replace it with our own

    Create a startup script /opt/etc/init.d/hotplugd with only one line:

    echo /opt/sbin/hotplug > /proc/sys/kernel/hotplug

    Then set it to run upon start up
    chmod a+x /opt/etc/init.d/hotplugd
    ln -s /opt/etc/init.d/hotplugd /opt/etc/init.d/S95hotplugd

    and check the result:
    cat /proc/sys/kernel/hotplug

    The output should be /opt/sbin/hotplug, which is our new event handler.

  2. Test drive hotplug
    So how does the hotplug work? below script will give you some idea to start with:
    Create /opt/sbin/hotplug with following:


    #For Debugging
    echo "Customized hotplug" >> /tmp/hotplug.log
    echo -------------$(date)----------- >> /tmp/hotplug.log
    set >> /tmp/hotplug.log

    set it as executable
    chmod a+x /opt/sbin/hotplug

    Unplug the printer, wait few seconds and plug the printer back.  Check the log by typing:
    cat /tmp/hotplug.log

    You can see there are bunch of environmental variables logged, two of them are worth noting:
    ACTION The value for "ACTION" variable can be "add" or "remove", corresponding to device plugin and removal.
    PRODUCT This is the unique device ID for the USB device, my printer is HP 1020 and value is 3f0/2b17/100.

    In a full Linux system, hotplug is much more complex. My script is a quick dirty hack but should be sufficient to handle USB printers.

  3. Configure hotplug to upload firmware to the printer
    Some GDI printer(aka Windows printer) will require extra work on Linux. Below is an example of my HP Laserjet 1020 but also applies to other HP laser printers like 1000, 1005, 1018, P1005, P1008, P1505 etc..
    You'll need two things to start with:
    The printer's firmware -- this must be in the printer before printing. Some of popular HP printers' can be downloaded from http://oleg.wl500g.info/hplj/
    usb_printerid -- this is used to detect if the firmware is already in place to prevent duplicated firmware uploading. Above link has one but that's for Broadcom devices. So I compile one for Atheros routers. Download here. Extract and put it to the router(samba, ftp or WinSCP).

    Assume we have the firmware in /opt/usr/local/lib/ and usb_printerid in /opt/usr/local/bin/, run
    chmod a+x /opt/usr/local/bin/usb_printerid

    And finally, here is the full script /opt/sbin/hotplug


    #For Debugging
    #echo "Customized hotplug" >> /tmp/hotplug.log
    #echo -------------$(date)----------- >> /tmp/hotplug.log
    #set >> /tmp/hotplug.log

    #replace it with your printer's firmware.

    if [ $DEVTYPE == 'usb_device' ] && [ $PRODUCT == '3f0/2b17/100' ]; then
    #replace with your printer's device id.
      if [  $ACTION == 'add' ]; then
        #check and upload firmware
        ${PRINTERID} /dev/usb/lp0 | grep -q FWVER || cat ${FIRMWARE} > /dev/usb/lp0
        #kill and restart p910nd
        kill -9 $(pidof p9100d)
        ${P910ND}  -b -f /dev/usb/lp0 0

      if [ $ACTION == 'remove' ]; then
        #printer removed, lets stop p910nd
        kill -9 $(pidof p9100d)

    The above script will upload firmware to printer then start p910nd daemon upon printer plug-in and stop p910nd when it's removed.

  4. Modified p910nd startup script
    With above script, DD-WRT will automatically configure the printer after the router is fully booted. However, similar approach has to be done during startup as the hotplug does not take effect at that moment.
    For unknown reasons, DD-WRT will NOT create /dev/usb/lp0 for printer even we have printer support enabled. As a result, we can't use this device node to detect the printer's presence.

    Here is a modified version of /opt/etc/init.d/p910nd startup script.

    source /mnt/root/.profile

    mkdir -m 755 -p /dev/usb
    mknod -m 660 /dev/usb/lp0 c 180 0
    sleep 1

    #replace with yours
    #printer name id string, see below

    i=$(find /sys/devices/platform/ -name product -exec cat {} \; | grep -c ${PNAME})

    if [ $i != '0' ]; then
         ${PRINTER_ID} /dev/usb/lp0 | grep -q FWVER || cat ${FIRMWARE} > /dev/usb/lp0
         kill -9 `pidof p9100d`
         ${P910ND}  -b -f /dev/usb/lp0 0

    Notice the PNAME='LaserJet' line. The 'LaserJet" is part of the printer's name and can be used to check if the printer is plugged. To determine yours, run

    find /sys/devices/platform/ -name product -exec cat {} \;

    The result looks like that:
    HP LaserJet 1020 #printer
    DataTravelerMini #USB flash drive
    Atheros AR91xx built-in EHCI controller #USB controller

After that, follow the previous tutorial to install printer in Windows if you haven't done so. Now enjoy the convenience of hotplug.


Printer Server for DD-WRT(the simple version)

With USB port on the router, a normal USB printer can be hooked and become a network printer with wired or wireless capabilities. As the router is usually on 24x7, there is no need to invest a (usually overpriced) dedicated printer server or plug the printer around.

The printer server program we use here is p910nd. It's a very small(only 8KB) daemon which simply redirects all printing command from PC to the printer.

Setting p910nd on the router can be a snap or very comprehensive depends on the printer. The best scenario would be sharing a Postscript/PCL compatible one and will be covered here.

Before start, you'll need a USB hub if your router has only one USB port as we now need to connect a USB drive and a USB printer. Unpowered hub is good for USB flash drive or hard drive with external power supply while I would suggest a powered hub for hard drive solely relied on USB power to prevent overload or damage to the HDD.

  1. Set DD-WRT support for USB printer
    If you haven't done so, check earlier post step #2. Make sure the USB printer support is selected.

  2. Install p910nd server and run it as a service
    Log in from PuTTY and run
    opkg install p910nd

    Now create /opt/etc/init.d/p910nd(delete all previous contents if the file is not empty)

    source /mnt/root/.profile
    mkdir -m 755 -p /dev/usb
    mknod -m 660 /dev/usb/lp0 c 180 0
    sleep 1
    kill -9 $(pidof p9100d)
    ${P910ND}  -b -f /dev/usb/lp0 0

    Then set it to run as a service

    chmod a+x /opt/etc/init.d/p910nd
    ln -s /opt/etc/init.d/vsftpd /opt/etc/init.d/S30p910nd

    Reboot or manually run /opt/etc/init.d/p910nd to make the change take effect.

  3. Install printer in Windows
    So we have p910nd running in the router now back to the PC(and Windows). First, you need to have the printer driver installed on the local computer. Exact procedures depend on the printer, but a foolproof way is to plug the printer back to PC then run manufacturer provided driver setup file.

    After driver installation, in Windows XP, follow this guide.

    Can't find a detail guide for Windows 7 but its essentially the same as earlier Windows editions. Anyway, here is a quick one:

    For Windows 7,  Open Control Panel->Hardware and Sound->Devices and Printers, then right click the printer icon. Select "Printer Properties" then click the "Ports" tab on the properties window.

    The default port might be USB001 that's for local USB port. Click "Add Port..." button, then select "Standard TCP/IP Port" from the list. Click "New Port..." which will open "Add Standard TCP/IP Printer Port Wizard". Click next and fill the "Printer Name or IP Address" with router's IP.
    After clicking "Next", Windows will try to detect the printer port and will fail. That's OK. On the next page, select "Custom" then click "Settings...". This will bring you another window, the default setting with Protocol Raw and Port Number 9100 should work. Confirm the change then back to original "Ports" tab. Select the newly added port as default and click "Apply".

    Now plug the printer back to router and try to print from Windows machine.

This is a ten-minute work if your printer is well supported aka. Linux friendly. However, things can get nasty for some GDI printer -- just name a few, the popular HP Laserjet 1010, 1018 and 1020. Also, you might want the p910nd to run only when the printer is connected. To solve all these problems, we need to make the router aware of printer's status change(plugging or removal) and run commands upon that. This is called hotplug and we can make some really neat solution with that.


vsftpd: FTP Server for DD-WRT

I generally prefer Samba over FTP as it gives a better experience by allowing user to access the files as if they're still on local disk. And, unlike FTP, media files can be played directly from Samba share. But one might still need FTP server as it offers better performance over Samba.

If the router has at least 8MB flash ROM and happens to run DD-WRT MEGA build, very likely there is a proftpd FTP server built in. But here I'll take some extra trouble to use lightweight vsftpd instead.

So why vsftpd? The main reason is its size. The proftpd is 500KB while vsftpd is only 100KB! This makes it perfect for embedded systems. Also, vsftpd is easy to use and setup.

  1. Disable stock ProFTPD server
    For DD-WRT, it's in Services->NAS. Set it to Disable then click "Apply Settings".

  2. Install vsftpd
    Assume you have followed previous tutorials and has a working opkg system, now use PuTTY to log in the router and run
    opkg install vsftpd

  3. (optional)Add a user for anonymous FTP access
    *ignore this part if you've follow the Samba guide, then this user is already in the system.

    Create or add to /opt/etc/init.d/adduser with following line:

    grep -q nobody /etc/passwd || echo 'nobody:x:65534:65534:nobody:/mnt:/bin/false' >> /etc/passwd

    Above is one single line and will create a new user "nobody" with no valid password and login shell(thus can't be used for login). Then set it to run during boot up:

    chmod a+x /opt/etc/init.d/adduser
    ln -s /opt/etc/init.d/adduser /opt/etc/init.d/S05adduser

  4. vsftpd.conf, the configuration file for vsftpd
    Edit file /opt/etc/vsftpd.conf with below(delete all previous contents if the file is not empty)

    #Change it if you want to use other port
    #Set it to NO if you don't want anonymous FTP access
    #local user used for anonymous FTP access, here is "nobody"

    For a full list of options, please refer to vsftpd website. These basic options here should be enough for home use. With the settings above, the anonymous user will be locked to "/mnt" folder(if you enable the anonymous option). Can also login with other valid user accounts like "root" or "share" with no restriction.

  5. Set vsftpd to run as a service
    Create file /opt/etc/init.d/vsftpd(delete all previous contents if the file is not empty)

    [ -d /var/run/vsftpd ] || mkdir /var/run/vsftpd
    kill -9 $(pidof vsftpd)
    vsftpd /opt/etc/vsftpd.conf

    Then set it to run as a service

    chmod a+x /opt/etc/init.d/vsftpd
    ln -s /opt/etc/init.d/vsftpd /opt/etc/init.d/S60vsftpd


Friday, June 25, 2010

Samba the File Share Server in DD-WRT

It's not an easy job to configure Samba share in standard DD-WRT because by default, the /etc folder is read-only. So before start, please following the previous tutorial to set a writable /etc. Also, might to your surprise, DD-WRT does have a Samba3 built in the firmware and it works just fine. In this article, you'll be guided through the whole process to set up a password protected samba share with customized username/password.

  1. Check if there is a Samba server built in
    Log in the router, then run
    smbd --version
    Output should be "Version 3.0.24", which means the firmware has Samba 3.0.24 included.
    If the Samba server is missing, install it by running
    opkg install samba3

  2. Add dedicated users for Samba
    For security reasons, I strongly suggest NOT to use "root" to access your Samba share. Instead, here we'll create users for Samba(and ftp) only with minimal privilege and no login shell.
    First, add the following lines to file /etc/passwd


    Save the /etc/passwd file, then run
    passwd share

    to change the password for user "share".  Now check the content of the updated /etc/passwd file, the line for user "share" will look like:


    The red part is the encrypted password. In the example line above, the password is also set to "share".

    To make the change permanent,  create a new script /opt/etc/init.d/adduser

    grep -q nobody /etc/passwd || echo 'nobody:x:65534:65534:nobody:/mnt:/bin/false' >> /etc/passwd
    grep -q share /etc/passwd || echo 'share:$1$2zhNidn9$DJK7SG8aqMg2hDsBYv6yZ.:65534:65534:share:/mnt/share:/bin/false' >> /etc/passwd

    Don't forget to change the red part. Then set it to run during boot up:
    chmod a+x /opt/etc/init.d/adduser
    ln -s /opt/etc/init.d/adduser /opt/etc/init.d/S05adduser

    The Home folder for user share will be /mnt/share, create it if its not present.

    mkdir -m 777 /mnt/share

    Then use smbpasswd to add a samba user with username "share" and password "share"

    mkdir /etc/samba
    touch /etc/samba/smbpasswd
    smbpasswd share share

    #replace the red part with your own password

    Copy the newly created /etc/samba/smbpasswd to /opt/etc/samba/smbpasswd to keep the /etc/ folder clean and in the future all configuration files will be stored in /opt/etc/samba folder. Please leave /etc/samba folder there(don't delete it) as its also required by Samba.

    mkdir -p /opt/etc/samba/
    cp -a /etc/samba/* /opt/etc/samba/
    chmod 644 /opt/etc/samba/smbpasswd

  3. smb.conf, the configuration file for Samba
    Use vi or nano, create file /opt/etc/samba/smb.conf with contents below:

            netbios name = DD-WRT
            workgroup = WORKGROUP
            server string = DD-WRT
            syslog = 10
            encrypt passwords = true
            passdb backend = smbpasswd
            obey pam restrictions = yes
            socket options = TCP_NODELAY
            preferred master = no
            os level = 20
            security = user
            guest account = nobody
            invalid users = root
            smb passwd file = /opt/etc/samba/smbpasswd
            unix charset = UTF-8
            dos charset = UTF-8
            comment = Home Directories
            browseable = no
            read only = no
            create mode = 0750
            path = /mnt/
            read only = no
            guest ok = no
            create mask = 0700
            directory mask = 0700

    Now test the file by running

    smbd -s /opt/etc/samba/smb.conf

    and access the Samba server by typing \\ in the address bar. Login with user "share". You should see two folders: "Share"(/mnt/share) and "USBDrive"(the whole /mnt folder).

    For Windows Vista/7 machine, a compatibility bit must be set to work with the Linux Samba share. See the end of the post.

  4. Run Samba as a service
    If everything works out, it's time for the startup script
    Create file /opt/etc/init.d/samba(delete all previous contents if its not empty).

    kill -9 $(pidof smbd)
    kill -9 $(pidof nmbd)
    /usr/sbin/smbd -s /opt/etc/samba/smb.conf
    #if you installed samba3 through opkg, use
    #/opt/bin/smbd -s /opt/etc/samba/smb.conf

    Then set it to run upon bootup:

    chmod a+x /opt/etc/init.d/samba
    ln -s /opt/etc/init.d/samba /opt/etc/init.d/S50samba

  5. (Optional)Fix Samba and Windows Vista/7
    When accessing Samba from a Windows Vista/7 machine, the password will always be rejected regardless whatever you input. That's because the Samba we used here does not support the new password authorization scheme in Windows.
    To fix:
    Run secpol.msc
    Go to: Local Policies -> Security Options
    Find "Network Security: LAN Manager authentication level" and change setting from "Send NTLMv2 response only" to "Send LM & NTLM - use NTLMv2 session security if negotiated"

    Some Windows versions may not have secpol.msc, in this case, save these 3 lines below to file sambafix.reg and run it:

    Windows Registry Editor Version 5.00

    Reboot the Windows to make the change take effect.


Thursday, June 24, 2010

Set DD-WRT to Use Local Time

This never looks to be a problem since DD-WRT provides such extensive options. Unfortunately, unlike Tomato and OpenWrt, which do a good job, DD-WRT's approach is way off and completely wrong.

A Linux box can keep its time in either local time or UTC -- both are fine as long as the corresponding time zone info is presented. However, in DD-WRT, the time zone info is completely missing and instead of standard implementing used in almost all Linux distros, DD-WRT  coins a weird scheme to setup(and keep) the time.

For example, 8AM PST(GMT-8) should be 4PM GMT, but a DD-WRT router would "think" the current time is 8AM GMT. Now if you change the time zone to EST(GMT-5), what will the router think? 11AM GMT!! Yes, that's after you've set all the "time zone" info in DD-WRT web management page. This is usually not a problem if you just want to use it as a router but for a Linux server, you definitely don't want to deal with any file created in future.

Now here is the fix:

  1. Disable DD-WRT's own NTP client
    From DD-WRT's web interface, Setup->Basic Setup, at the bottom of the page, disable the whole NTP part.
    Then click "Apply Settings"

  2. Install our own NTP client
    Use PuTTY to login the router, then run

    opkg install ntpclient

    Then we need to get the newly installed ntpclient running as a service. To do so, use vi or nano and create a file named /opt/etc/init.d/ntpclient

    source /mnt/root/.profile
    /opt/usr/sbin/ntpclient -i 600 -D -s -l -h pool.ntp.org -p 123
    #600 means it will sync every 10 minutes(600 seconds)
    #pool.ntp.org is the NTP server to use

    Give it executable permission and then set it to run on start up.

    chmod a+x /opt/etc/init.d/ntpclient
    ln -s /opt/etc/init.d/ntpclient /opt/etc/init.d/S20ntpclient

  3. Set time zone info for DD-WRT
    First, we need to create the /etc/TZ file with proper time zone info

    echo PST8PDT,M3.2.0,M11.1.0 > /etc/TZ

    The red part an example(US Pacific) and the full list can be found here(the time zone table). Replace it with yours accordingly. And, don't worry about daylight saving time, it's already taken care of.

    We also need to set the TZ variable by adding a line in /mnt/root/.profile

    export TZ=$(cat /etc/TZ)

    Finally, there is a hidden nvram value used by DD-WRT internally, it's also needed to be fixed or the web page will display a wrong time. From PuTTY, run:

    nvram set time_zone=PST8PDT,M3.2.0,M11.1.0
    nvram commit

    #replace the red part with yours.

It's done. Reboot the router and login with PuTTY, type date to check the output. DD-WRT should start using local time now.


Software Installation on DD-WRT -- Part 2

In previous part, we have everything settled(almost). Now its the time for some more fine tune.

By employing the techniques in Part 1, we have the following setup upon each reboot:

  • A USB drive mounted and accessible at /mnt
  • A writable /etc folder(actually /mnt/etc) and has exact same content as original /etc folder
  • A writable /opt folder(actually /mnt/opt) -- where all future software will be installed and run from(/opt/bin, /opt/sbin, /opt/usr/bin, just name a few) and keep the original DD-WRT folders like /bin /sbin untouched.
  • A writable and persistent /tmp/root(actually /mnt/root). This will be the home folder for user root
  • An empty file /mnt/optware.enable. This is used to control the whole optware installation. By renaming or deleting this file, all customized software/modification WILL BE DISABLED and thus put the router back to standard DD-WRT. This is useful for debugging and firmware upgrading.

Still, there is something left to do, notably that, with current setup, the LD_LIBRARY_PATH and PATH variables have to be set each time before running any command. We might also want to run some installed software as service.

  1. Set the initial variables
    Login with PuTTY then copy/paste the commands below to PuTTY window to create a script running each time when user root logins.

    cat > /mnt/root/.profile << EOF
    export LD_LIBRARY_PATH='/opt/lib:/opt/usr/lib:/lib:/usr/lib:/opt/usr/local/lib'
    export PATH='/sbin:/opt/bin:/opt/usr/bin:/opt/sbin:/opt/usr/sbin:/bin:/usr/bin:/usr/sbin:/opt/usr/local/bin'
    export PS1='\[\033[01;31m\]\u@\h \[\033[01;34m\]\W \$ \[\033[00m\]'
    export TERMINFO='/opt/usr/share/terminfo'

    The above script will set the variables for us and also provide a nice colored command line prompt. Now exit the current PuTTY window and connect again, if you see a colored prompt then it's working correctly. Run
    opkg update
    directly and it should work now -- no need to set the lengthy variables each time. Also, if you're not familar with vi, time to get the nano editor
    opkg install nano
    Then type nano to launch it.

  2. Run installed software as service
    In previous guide(Part 1), our DD-WRT startup script does nothing more than mounting several folders. We don't use it to launch any programs simply because its not necessary as DD-WRT has a feature that, it will run any script during startup automatically once it's in correct location with correct name.

    To run a script with our current setup, all we need to do is to put the scripts to /opt/etc/init.d folder and name them in the format of S##ScriptName. The ## is two digit from 00 to 99, script with smaller number will run first. For example, to run Samba file server and p910nd printer server as services, we just need to create two startup script
    then make symbolic links:
    ln -s /opt/etc/init.d/p910nd /opt/etc/init.d/S30p910nd
    ln -s /opt/etc/init.d/samba /opt/etc/init.d/S50samba


    and p910nd will start up first then samba. And, in case you don't need them as service, delete the symbolic links(S30p910nd/S50samba) but keep the original startup script so it can be easily recovered. The program can also be launched directly by running the corresponding script(/opt/etc/init.d/p910nd and /opt/etc/init.d/samba)
    Guide for Samba server and the p910nd printer server will be detailed in future articles. This is just to get you an idea how the startup control system works.


Software Installation on DD-WRT -- Part 1

One thing interesting about the router is its exotic hardware specification -- 400MHz processor, 32MB flash ROM, 64MB RAM and most important of all, a USB port. All these make the router a very versatile little Linux box with tons of capabilities. However, one thing might confuse non-experienced users is that, the CPU in the router is MIPS(MIPS in big-endian), while the popular Broadcom routers(such as Linksys WRT54G) are MIPSEL(MIPS in little-endian). I don’t want to go into technical detail here, but just remember, even both are MIPS, they’re different and prebuilt binary for Broadcom routers WILL NOT work on this WZR-HP-G300NH and other Atheros based devices.

Thanks to the OpenWrt guys, with some effort, we can now put the OpenWrt binary on this router and it will run as good as the popular “optware”.

In this tutorial, I'll guide you through the process and all software will be installed on USB disk though the Buffalo router has a gorgeous 32MB flash ROM. The reason is simple – the flash ROM jffs partition will NOT survive during a firmware upgrade and you definitely don’t want to reinstall everything again each time. Also, USB disk is much faster than internal flash.

This guide will also work with other USB enabled Atheros routers such as TP-LINK TL-WR1043ND, Linksys WRT160NL, D-LInk DIR-825 RevB and Netgear WNDR3700

  1. Prepare the USB disk
    Here we can use a USB flash drive or a USB hard drive and the drive must be preformatted to ext2 or ext3(recommended) before plugging into the router.
    Any Linux live CD should do the trick and I personally recommend GParted, which can be installed in CD or USB disk.

  2. Set up DD-WRT accordingly
    a. Turn on ssh.
    This is under Services->Service->Secure Shell. See the picture below. Then click “Apply Settings” at the bottom of the page.

    b. Set USB Support
    Under Services->USB tab. Will disable “Automatic Drive Mount” here. After that, click “Apply Settings”usb-enable

    c. Disable the jffs partition
    Under Administration->Management, disable “JFFS2 Support”. After that, click “Apply Settings”.

  3. Download WinSCP, PuTTY and prebuilt libraries
    WinSCP is used to copy file between PC and router and PuTTY is for router shell login. Both are freeware.
    Also, you’ll need some prebuilt OpenWrt libraries called lib.tar(thanks Luyi@DD-WRT forum check original discussion thread)
    Get it from DD-WRT forum(login required) or mirror site.

  4. Now plug in the USB drive and reboot the router.

  5. After rebooting, login the router with PuTTY.
    Fill in router’s IP( in most cases), left everything else on default(port 22 and Connection type SSH) and click “Open”.
    The login username is always root and password is the web password you set.

  6. Mount the USB drive
    Type the command in PuTTY window
    ls /dev/discs/disc0/
    and the result might look like this
    Now here is the tricky part. If you’re using a USB flash drive with only one partition, most likely, you will only see “disc” but not “part1” and “part2”. If you’re using a USB HDD with multi partitions you might expect an output similar to mine. Both are OK.

    If you see “disc” only, use the command line below to mount an ext3 USB drive to /mnt
    mount -t ext3 -o noatime /dev/discs/disc0/disc /mnt
    *Use mount -t ext2 /dev/discs/disc0/disc /mnt for ext2 drive

    For USB drive with multi partition, the command below will mount the first partition to /mnt. Adjust accordingly.
    mount -t ext3 -o noatime /dev/discs/disc0/part1 /mnt
    *Use mount -t ext2 /dev/discs/disc0/part1 /mnt for ext2 partition

  7. Now create and prepare necessary folders
    Type the commands below in PuTTY

    cd /mnt
    mkdir etc opt root
    touch optware.enable
    chmod 755 etc opt root
    mkdir opt/lib
    chmod 755 opt/lib
    cp -a /etc/* /mnt/etc/
    mount -o bind /mnt/etc /etc
    mount -o bind /mnt/opt /jffs

    So now we have a writable /etc and /jffs folders while they both reside in the USB drive. All other folders -- especially /bin, /usr and /sbin – will be left untouched to keep the change minimal. The /etc folder will also be handled with extra caution.

  8. Extract lib.tar and upload all files to router’s /jffs/lib folder by using WinSCP.
    Same as PuTTY, the username will always be root, the file protocol must be set to SCP. See the picture below
    After that, ignore all warning messages and click “yes” all the way. You’ll see the file transfer Window then. Also please refer to DD-WRT Wiki if there is any other question.

    Now extract lib.tar(using WinRAR or 7Zip) and upload everything to router’s /jffs/lib folder.

    In the Putty window, run
    ls /jffs/lib
    to make sure all files are uploaded, then run
    chmod a+x /jffs/lib/*
    to set the properties.

  9. Install OpenWrt’s opkg
    Now in the PuTTY window, type

    cd /tmp
    wget http://downloads.openwrt.org/backfire/10.03/ar71xx/packages/opkg_513-2_ar71xx.ipk
    ipkg install /tmp/opkg_513-2_ar71xx.ipk

    After that, run the command to create the configuration file for newly installed opkg

    cat > /etc/opkg.conf << EOF
    src/gz snapshots http://downloads.openwrt.org/snapshots/trunk/ar71xx/packages/
    dest root /opt
    dest ram /tmp
    lists_dir ext /tmp/var/opkg-lists

    Also notice the underlined /opt. In the future, all software will be installed to /opt folder in case some might still want to use internal flash. The /jffs folder is only necessary for initial setup.

  10. Set the startup script to make the changes take effect each time upon reboot
    Under DD-WRT’s web interface, Administration->Commands,  input the following command in the window then click “Save Startup”


    sleep 5
    #mount -t ext3 -o noatime /dev/discs/disc0/disc /mnt
    mount -t ext3 -o noatime /dev/discs/disc0/part1 /mnt
    #choose one for your drive, see Step #6

    sleep 2
    if [ -f /mnt/optware.enable ]; then
    mount -o bind /mnt/etc /etc
    mount -o bind /mnt/root /tmp/root
    mount -o bind /mnt/opt /opt

    if [ -d /opt/usr ]; then
    export LD_LIBRARY_PATH='/opt/lib:/opt/usr/lib:/lib:/usr/lib'
    export PATH='/opt/bin:/opt/usr/bin:/opt/sbin:/opt/usr/sbin:/bin:/sbin:/usr/sbin:/usr/bin'

    Reboot to make the change take effect.

  11. Test opkg package system
    After reboot, login with PuTTY again, run

    export LD_LIBRARY_PATH='/opt/lib:/opt/usr/lib:/lib:/usr/lib'
    export PATH='/opt/bin:/opt/usr/bin:/opt/sbin:/opt/usr/sbin:/bin:/sbin:/usr/sbin:/usr/bin'
    opkg update

    to check if opkg(the OpenWrt’s variant of ipkg) is installed and working properly.
    Then install/upgrade some base libraries and the busybox utility

    opkg install libc
    opkg install libgcc
    opkg install uclibcxx
    opkg install libncurses

    opkg install busybox

Almost done! There’re still some work and fine tune left which will be covered in the next part.


Wednesday, June 23, 2010

Firmware flash and brick recovery through TFTP

Though the whole flashing process can be done via Web interface(dd-wrt to stock and vice versa) without getting your hands dirty, still, there're cases that the Web flashing is not sufficient. One common scenario is a bricked WZR-HP-G300NH, i.e., no web access and no ping response due to bad firmware or wrong operation, or you just want to try other firmware like OpenWrt. Luckily that the WZR-HP-G300NH has a robust bootloader and the router can be recovered by using TFTP, either in Windows, Linux or OSX.

It's a little tricky comparing to traditional Broadcom routers, as the WZR-HP-G300NH will not broadcast its MAC during initial bootup process, as a result, we must tell the computer how to communicate with the router by manipulating its arp table.

TFTP recovery in Windows
*Untested, credit goes to ermax at D-WRT forum
  1. Get your router's MAC, its the 12 digit default SSID printed on the sticker at the back of the router, starting with 00. Then you'll need to break it down every two digit by inserting : or - between them.
  2. Download the latest official firmware(in case of recovery) from Buffalo's official website. Extract to get the firmware, in my case, its 1.74 and the firmware name is wzrhpg300nh-174, ~20MB.

    Also download the
    Linksys TFTP utility.
  3. (May not necessary) Do a hard reset or 30/30/30 on the router.
  4. Unplug all the ethernet cable and the power cable and connect the computer directly to the router(still leave it off)
  5. Set the computer's static IP to, netmask, gateway/DNS
  6. Open a Windows command prompt as Administrator. This is default on Windows XP, under Windows Vista/7, type cmd in the search box from Start menu, then press Ctrl+Shift+Enter. You will be prompted with the User Account Control dialog.
  7. Type route print to get a list of your NIC(s). Write down the interface number for the LAN card, in my case, it's 12.
  8. Now type the command below to get the ARP binding(thanks ermax at DD-WRT forum):

    netsh interface ipv4 add neighbors 12 00-1d-12-34-56-78

    Replacing the number 12 with the interface number and 00-1d-12-34-56-78 with the router's MAC address.
  9. Run Linksys TFTP utility. Put as Server address, Password empty, File is wzrhpg300nh-174 just extracted, set retry time to 30.
  10. Click "Upgrade" in the TFTP utility and quickly plug the power back to turn on the router. There might be few failed attempts but the flash process should start later. Wait patiently the router will reboot itself when the upgrade is done. Navigate to stock firmware) to configure your router.

TFTP recovery in Linux
*Most of this part is from DD-WRT wiki with some tweak. TEST WORKING

Will use Ubuntu Live CD as an example but other distro should also work. The Ubuntu LiveCD can be booted from a USB flash drive. See here.

  1. Do Step 1-4 in "TFTP recovery in Windows" except we don't need Linksys TFTP utility here. So we have MAC address ready, router unpowered and the computer is directly connected to the router.
  2. After booting into Ubuntu, open a terminal and type:

    sudo apt-get update
    sudo apt-get install tftp-hpa
    sudo /etc/init.d/networking stop
    sudo ifconfig eth0
    sudo ifconfig eth0 netmask
    sudo arp -s 00:1D:12:34:56:78
    #change to the folder where you put the firmware image, if it's on desktop then it's
    cd /home/ubuntu/Desktop
    *from this point, you're under tftp command prompt, the "tftp>" is the prompt tftp gives you, you just need to type the command AFTER that.
    tftp> verbose
    tftp> binary
    tftp> trace
    tftp> rexmt 1
    tftp> timeout 60
    tftp> put wzrg300nh-firmware.tftp

    Replace the fictional MAC in red with the router's. All command you need to input is in italic. Also replace wzrg300nh-firmware.tftp with the firmware you need, in case of stock firmware, its wzrhpg300nh-174.

    Also, at this point, the router is still unpowered and that's OK. Tftp will keep trying to send the firmware to the router and when it fails (because the router isn't yet on or hasn't yet brought up it's tftp interface) it will wait 1 second and retry, up to 60 times as that's how we set up the tftp client.
  3. Now quickly plug the power cord back to the router. The router will start up and you will see some lights blinking (possibly). About 10-20 seconds in, you should notice that tftp is sending the file. instead of the retry message over and over you will see some progress scrolling down the screen and at the end it will tell you how many blocks or bytes were transferred in how many second.
  4. After the transfer is complete, wait about 5-10 minutes the router will reboot itself. When the wireless LED is on you're good to go.
  5. Bring the network back in Linux by typing

    sudo service networking start
TFTP recovery in OSX
*Untested, credit goes to BDawg at DD-WRT forum
  1. Do Step 1-4 in "TFTP recovery in Windows" except we don't need Linksys TFTP utility here. So we have MAC address ready, router unpowered and the computer is directly connected to the router.
  2. Set the computer's static IP to, netmask, gateway/DNS
  3. Open a terminal and type

    sudo arp -s 00:1D:12:34:56:78 ifscope en0

    Replace with your own router's MAC.
  4. Type


    tftp> put wzrhpg300nh-174

    Don't press Enter
  5. Now plug the power cord back and hit Enter to start tftp transfer.


Monday, June 21, 2010

Flash between DD-WRT and official firmware on WZR-HP-G300NH

Flashing DD-WRT on this router is extremely easy now -- thanks to the hard work of DD-WRT developers and the officially partnership with Buffalo.

Flash from the stock firmware to DD-WRT
*Use releases after r14402 to be safe as earlier releases had some problem with certain WZR-HP-G300NHs and might brick the router(can be recovered).

Goto DD-WRT Router Database and type WZR-HP-G300NH in the search box. There are two files listed:
  • buffalo_to_ddwrt_webflash-MULTI.bin
    This is used to upgrade from stock firmware to dd-wrt, which includes an encrypted file header to make it compatible with Buffalo's official web upgrade page. Use it when flashing from stock firmware to dd-wrt.

  • wzr-hp-g300nh-dd-wrt-webupgrade-MULTI.bin
    This is for future update from a DD-WRT loaded router.
The upgrade process is very straightforward and there is really nothing to elaborate here. Just load buffalo_to_ddwrt_webflash-MULTI.bin on the firmware upgrade page then wait patiently. Also note that the router's IP will change from's stock firmware) to, use DHCP or set the static IP accordingly.

Revert DD-WRT to stock firmware

DD-WRT for this router is still in early stage so one might want to back to the stock firmware. We can always go through the bulletproof TFTP route but if you just need to revert from DD-WRT, there is a shortcut.
  1. Download this modified Buffalo firmware(mirror download)
    Its a stock 1.65 firmware and has been modified to work with DD-WRT web upgrade interface. The firmware is on DD-WRT forum and you'll need to register to download it. Or you can download from the mirror link without registration.

  2. Load file wzrg300nh_original.bin within DD-WRT web upgrade page to do the conversion. Be patient, it longer than usual and will take like 5-10 minutes.

  3. After reboot, router's IP will change from -- if you're using DD-WRT's default -- to

  4. The router will now have firmware 1.65 loaded and you can upgrade it to newer release from this point. Save wzrg300nh_original.bin for future use if you're about to try DD-WRT(again)


Friday, June 18, 2010

About WZR-HP-G300NH and this blog

Have been looking for a new router to replace my old trusty WRT54G-TM(the T-Mobile version of WRT54GS v3) since early this year. My case might be somewhat unusual than others, as besides standard routing jobs, this router will also serve as a 24x7 Linux box, so open source firmware compatibility is a must.

To keep up with today's standards I made a checklist for my purchase:
  1. Open source firmware support
    DD-Wrt, OpenWrt or Tomato...Well...Linux FTW :)

  2. 11N Wireless+Gigabit LAN

    802.11N capable router is getting cheaper today and the performance boost over the old 802.11G is phenomenal. Its not hard to get at least 4-5MB/s even in a crowded apartment with tons of 2.4G AP around.

    For Gigabit LAN, one might think you need expensive cat6 cable to get it working, while in my test, I get ~60MB/s in real world file transferring, which I believe the speed is actually limited by the (slow) notebook hard drive. In Iperf theoretical test, I get around 900Mb/s throughput -- and its all on some old cat5e cables.

  3. USB ports for storage and printer
    More storage means more possibility. There're lots we can do with the USB ports, right now, I made it a samba file server and a wireless 11N printer sharing server.

  4. At least 4MB of flash ROM and 32MB of RAM
    This is not really a problem for today's 11N router expect a few(DIR-655 comes to mind). Anyway, Linux likes RAM, the more the merrier.

  5. Reasonable price, sub $100
And I finally laid eyes on the routers below:
  • Netgear WNR3500L
    Broadcom based router with a powerful 480MHz CPU, 8MB Flash/32MB RAM and USB port. Street price $90.

  • ASUS RT-N16
    Also Broadcom based and same processor as 3500L(BCM4718@480MHz, initial press release said 533MHz but the final product is downclocked to 480 due to overheating). 32MB Flash and 128MB RAM. Street price $90-$100.

    Atheros based solution with 3T3R antenna. 400MHz AR9132 CPU, 8MB ROM and 32MB RAM. Street price is $60-$70.

  • Buffalo WZR-HP-G300NH
    Similar spec with the TP-Link WR1043ND except 32MB ROM and 64MB RAM. Street price is $80-$90.
Linksys routers are not on my list because they're seriously overpriced, for example, the WRT160NL, same CPU/ROM/RAM as the TP-Link WR1043ND but only 100Mb switch and Linksys wants $90 for that!

Anyway, I go for Atheros based solution mainly because of the ath9k opensource driver. Comparing to the proprietary Broadcom binary blob, its almost no-brainer for a long time OpenWrt user like me. Also, the Atheros based routers, namely the WZR-HP-G300NH and TL-WR1043ND, are using Realtek switch with Jumbo frame support, which is also a big plus.

Between TP-Link and Buffalo, I went for Buffalo for the extra 32MB RAM. Others might find the "HP"(High Power) to be useful as well.

The router was bought on March, shortly after the announcement of OpenWrt and DD-WRT support. Still, as of today, very few documents are available on the G300NH(and other Atheros based routers) so I decided to put this blog to record and share my work.