Posted by on 7 Feb 2013 in Hardware, Reversing, Security | 3 comments

A post on the (aptly named) /dev/ttyS0 device hacking blog entitled "Reverse Engineering Serial Ports" reminded me that I had an AMX NXA-WAP250G Wireless Access Point that I’d been meaning to investigate for some time. I thought I’d document the process I went through while reverse engineering it, in the hope that it’s interesting or useful to someone.
AMX WAP-250G

The Firmware

Not having the device to hand, I started with what I could find out from a saved firmware update – a file named zz-img.bin, dated 2008-08-04 and 1,350,968 bytes in size. I went with what’s usually my first instinct in situations like this, and tried the file command:

$ file zz-img.bin
zz-img.bin: ELF 32-bit MSB executable, MIPS, MIPS-II version 1 (SYSV), statically linked, stripped

It seemed likely the firmware image was actually a MIPS-architecture ELF, in which strings showed some strong indications that zlib compression was present:

$ strings zz-img.bin
oversubscribed dynamic bit lengths tree
incomplete dynamic bit lengths tree
oversubscribed literal/length tree
incomplete literal/length tree

I’ve omitted the other 14,000 lines of output!

As the only human-readable strings of characters in the output, they were quite obvious. They’re likely to be immediately recognisable to anyone who has reverse engineered firmware before, but a simple Google 1 search for any of them would be enough to come to the same conclusion.

Hoping to find out what was hiding compressed inside the file, I tried running binwalk over it; that told me nothing I didn’t already know – that I was looking at a MIPS ELF. Slightly disheartened, I hacked together a trivial Python program to naively step through the firmware image, repeatedly calling zlib.decompress until it succeeded without error, or the end of the file was reached.

A moment later, starting 19,569 bytes from the beginning of the file, decompression was successful. I now had 3,303,265 bytes of output saved to a file imaginatively named zz-img.out; file didn’t recognise it but binwalk claimed had 88 identifiable components:

$ binwalk zz-img.out

DECIMAL     HEX         DESCRIPTION
-------------------------------------------------------------------------------------------------------
1062235     0x10355B    LZMA compressed data (sig 2), properties: 0x5D, dictionary size: 554696704 bytes, uncompressed size: 50372624 bytes
2339492     0x23B2A4    Zip archive data,  v0.0
2380548     0x245304    GIF image data, version 89a, 69 x 23
2381732     0x2457A4    GIF image data, version 89a, 1 x 1
2382466     0x245A82    TIFF image data, little-endian
2464692     0x259BB4    GIF image data, version 89a, 69 x 23
2465938     0x25A092    TIFF image data, little-endian
2466722     0x25A3A2    TIFF image data, little-endian
2467538     0x25A6D2    TIFF image data, big-endian
2534356     0x26ABD4    GIF image data, version 89a, 69 x 23
2535636     0x26B0D4    GIF image data, version 89a, 69 x 23
2536866     0x26B5A2    TIFF image data, little-endian
2542338     0x26CB02    TIFF image data, little-endian
2545572     0x26D7A4    GIF image data, version 89a, 69 x 23
2546740     0x26DC34    GIF image data, version 89a, 69 x 23
2809172     0x2ADD54    GIF image data, version 89a, 32 x 32
2898498     0x2C3A42    TIFF image data, little-endian
2988972     0x2D9BAC    LZMA compressed data (sig 2), properties: 0x5D, dictionary size: 687865856 bytes, uncompressed size: 10 bytes
2996232     0x2DB808    Linux Journalled Flash filesystem, little endian
3021080     0x2E1918    gzip compressed data, was "HACL.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:05 2004
3021992     0x2E1CA8    gzip compressed data, was "HCfg.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:05 2004
3022612     0x2E1F14    gzip compressed data, was "HQos.htm", from NTFS filesystem (NT), last modified: Tue Sep 14 09:39:59 2004
3023176     0x2E2148    gzip compressed data, was "HSecurity.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:05 2004
3023852     0x2E23EC    gzip compressed data, was "HServer.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3024468     0x2E2654    gzip compressed data, was "HSetup.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3025208     0x2E2938    gzip compressed data, was "HSetupAv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3026100     0x2E2CB4    gzip compressed data, was "HWpa.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3026644     0x2E2ED4    gzip compressed data, was "Hfw.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3027024     0x2E3050    gzip compressed data, was "Hfwadv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:06 2004
3027696     0x2E32F0    gzip compressed data, was "Hradio.htm", from NTFS filesystem (NT), last modified: Tue Sep 14 04:13:29 2004
3028572     0x2E365C    gzip compressed data, was "Hsetup2.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3029060     0x2E3844    gzip compressed data, was "about.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3029296     0x2E3930    gzip compressed data, was "ap_stats.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3030240     0x2E3CE0    gzip compressed data, was "cfgscr.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3031228     0x2E40BC    gzip compressed data, was "configs.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:07 2004
3032416     0x2E4560    gzip compressed data, was "index.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3033104     0x2E4810    gzip compressed data, was "lastupld.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3033376     0x2E4920    gzip compressed data, was "privacy.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3034432     0x2E4D40    gzip compressed data, was "privedit.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3036020     0x2E5374    gzip compressed data, was "privnew.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:12 2004
3037940     0x2E5AF4    gzip compressed data, was "qos.htm", from NTFS filesystem (NT), last modified: Tue Sep 14 08:43:01 2004
3039708     0x2E61DC    gzip compressed data, was "radio.htm", from NTFS filesystem (NT), last modified: Thu Sep 16 12:04:50 2004
3041244     0x2E67DC    gzip compressed data, was "reboot.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:13 2004
3041580     0x2E692C    gzip compressed data, was "rstcfg.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:13 2004
3041828     0x2E6A24    gzip compressed data, was "scanning.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:13 2004
3042136     0x2E6B58    gzip compressed data, was "security.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:14 2004
3044496     0x2E7490    gzip compressed data, was "server.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:14 2004
3045708     0x2E794C    gzip compressed data, was "setleft.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3046316     0x2E7BAC    gzip compressed data, was "setup.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3047624     0x2E80C8    gzip compressed data, was "setup2.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3049028     0x2E8644    gzip compressed data, was "setupadv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3050884     0x2E8D84    gzip compressed data, was "setupfr3.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:15 2004
3051220     0x2E8ED4    gzip compressed data, was "stafr3.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3051592     0x2E9048    gzip compressed data, was "stafr3a.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3051968     0x2E91C0    gzip compressed data, was "stafr3b.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3052348     0x2E933C    gzip compressed data, was "staleft.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:16 2004
3053180     0x2E967C    gzip compressed data, was "stalist.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:17 2004
3053920     0x2E9960    gzip compressed data, was "stastats.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:17 2004
3055432     0x2E9F48    gzip compressed data, was "survey.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:17 2004
3056192     0x2EA240    gzip compressed data, was "upldadv.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3057888     0x2EA8E0    gzip compressed data, was "upldprog.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3058180     0x2EAA04    gzip compressed data, was "upldstat.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3059028     0x2EAD54    gzip compressed data, was "upload.htm", from NTFS filesystem (NT), last modified: Fri Aug 13 05:44:18 2004
3060464     0x2EB2F0    gzip compressed data, was "wpa.htm", from NTFS filesystem (NT), last modified: Fri Sep 10 04:32:37 2004
3061812     0x2EB834    GIF image data, version 89a, 1 x 1
3061856     0x2EB860    GIF image data, version 89a, 61 x 25
3062528     0x2EBB00    GIF image data, version 89a, 88 x 25
3063412     0x2EBE74    GIF image data, version 89a, 77 x 25
3067216     0x2ECD50    GIF image data, version 89a, 61 x 25
3067936     0x2ED020    GIF image data, version 89a, 364 x 390
3072756     0x2EE2F4    GIF image data, version 89a, 460 x 235
3120580     0x2F9DC4    GIF image data, version 89a, 39 x 15
3121012     0x2F9F74    GIF image data, version 89a, 77 x 25
3121820     0x2FA29C    GIF image data, version 89a, 1 x 1
3121864     0x2FA2C8    GIF image data, version 89a, 179 x 120
3127352     0x2FB838    GIF image data, version 89a, 54 x 40
3127656     0x2FB968    GIF image data, version 89a, 95 x 40
3128144     0x2FBB50    GIF image data, version 89a, 1 x 40
3128192     0x2FBB80    GIF image data, version 89a, 72 x 40
3128584     0x2FBD08    GIF image data, version 89a, 94 x 25
3129540     0x2FC0C4    GIF image data, version 89a, 77 x 25
3130348     0x2FC3EC    GIF image data, version 89a, 77 x 25
3131156     0x2FC714    GIF image data, version 89a, 1 x 1
3131200     0x2FC740    GIF image data, version 89a, 270 x 80
3132364     0x2FCBCC    GIF image data, version 89a, 61 x 25
3133136     0x2FCED0    GIF image data, version 89a, 61 x 25
3211978     0x3102CA    Linux Journalled Flash filesystem, little endian

(I initially tried binwalk v0.4.3 which output over a hundred false positive “JFFS” and “LZMA” entries. The output shown is from v0.5.0 which is much more accurate, on this sample at least.)

Of those, the gzipped ones looked like they could be interesting, with plausible names and modification dates. Using the dd and gunzip commands, I extracted one (though I understand the latest version of binwalk can do this itself) but the resulting HTML file turned out to be a fairly uninteresting part of the access point’s web interface.

Moving on, I tried strings again on zz-img.out. This time, operating on uncompressed data, the output was much more useful.

There were many references to VxWorks:

VxWorks5.4.2
Jul 11 2008, 15:37:45

Boot parameters:

j8tffs:(0,0):/fl/zz-img.bin f=0x00 e=192.168.1.240:0xffffff00 o=ae g=192.168.1.254 s=factory
AR531XPLUS
unknown boarddata rev!
Atheros AR5315 default

There appeared to be a command line interface, complete with help:

Type "help" for a list of valid commands.

Some of which looked particularly interesting:

Searching for BSS
find
connect to BSS X
connect
Copy file
Boot parameters
boot
Temporary factory admin
admin

One of the other strings stood out too, “OWOWOWOWOWOWOWOW”. Amusingly, a Google search for that string led me straight back to another post on the /dev/ttyS0 blog about a mystery VxWorks filesystem (later identified as MemFS).

At this point, I considered it was fairly likely the device was running VxWorks, had a command line interface of some sort, and that if it came to it, modifying the existing firmware update was at least plausible. There’s much more I could have investigated in the firmware – perhaps starting with that MemFS filesystem – but by this point I’d managed to find the actual device itself and was eager to open it up and see what it looked like inside.

The Hardware

As it turned out, I could have probably skipped the firmware analysis and jumped straight to powering the device up and taking it to pieces (not necessarily in that order).

AMX WAP-250G Board

Any router hackers out there will no doubt find that board familiar; it looks just like a Fonera 2100. The FON2100 router is based on the Atheros AR5315 SoC, which matched up with what I’d seen in my firmware analysis. The part numbers of the Hynix HY57V281620ETP-H memory is also consistent, while the ST 25P32V6P flash chip is slightly different.

From some further research, I discovered that the Fonera 2100 is actually an Accton MR3201A in disguise. The Edge-Core WA3101, Philips SNR6500, SMC WEBT-G, Siemens Gigaset WLAN Repeater 108, and the Meraki Mini all appear to be slightly (if that) modified versions of the same design. This was great news, because it meant reverse engineering my esoteric router would be enormously simpler than I might have expected – there’s plenty of information about those other routers about there, particularly concerning running Linux on them.

Delving into the information that the OpenWRT and DD-WRT projects had about these routers, I found out that most, if not all, of them had an ST 25P64V6P – 8MB – flash, while the WAP250G has a 25P32V6P with only 4MB capacity. That was annoying, but among the many published hardware hacks is an SD card mod which would massively improve the amount of storage available.

Aside from some fanciful ideas about future hardware modifications, the most pertinent information I’d found out was that Fonera’s serial port pinout is well known and published. To connect to it, I needed something that would talk serial at TTL signal levels (3.3V) and not RS-232 (somewhere around 15V). Just as I was considering cutting up a USB phone cable, I realised that I had a full-blown Linux system with a handily accessible serial port that runs at the correct voltage – my Raspberry Pi.

The Raspberry Pi

I cut up and soldered together some cables from an old PC case that would previously have connected the external buttons to the PC’s motherboard – the ones that would have gone to the HDD LED and reset switch of the PC are quite obvious in the picture below. The GPIO pins of the Pi are well documented and the OpenWRT page about the Fonera includes its serial pinout, which I confirmed with a multimeter, as described in the post that set me off with this whole project.

With Raspbian Wheezy running on the Pi, using the serial port was quite straightforward. I had to edit cmdline.txt on the SD card to disable the serial console on /dev/ttyAMA0, otherwise the Pi would be outputting kernel messages over it as it booted up. Likewise I commented out the getty line from /etc/inittab on the system to prevent it from issuing a login prompt over the serial port.

With the Pi connected to the powered-up router as pictured above, I fired up minicom, told it to connect to ttyAMA0 with the baud rate 9600 and 8N1 (rarely a bad guess) and gingerly tapped “enter”.

I was instantly greeted with a login prompt. Neat! I knew from the 250G’s documentation what the web interface default credentials were, so I tried those – ‘Admin’ and ’1988′:

AP login: Admin
Password: ****

ACCTON Access Point Rev v1.0.6.0
wlan[0,0] -> help
List of Access Point CLI commands:
wlan[0,0] ->

As you can see, the serial connection works, the login was successful but the ‘help’ output I initially found while examining the firmware was absent. I tried on of the commands I’d seen in that help text:

wlan[0,0] -> version
AP software v1.0.6.0

That worked, so it seemed like the ‘help’ might be correct, so I wasn’t sure why I couldn’t see it. Looking back at that help text for some other commands to try, one in particular stood out – ‘admin’. The line above it – presumably the description of the command – said “Temporary Factory admin” so I tried it:

wlan[0,0] -> admin
Password: ****
Sorry
wlan[0,0] -> admin
Password:
Ok

It asked me for a password; I tried ’1998′ which was incorrect. Just as I was considering loading the firmware up in IDA or looking through it for more suspicious looking strings, I tried again and just hit enter – a blank password. That worked!

Interestingly, after using the ‘admin’ command, ‘help’ now works and outputs the full unabridged text I had extracted from the firmware earlier:

wlan[0,0] -> help
List of Access Point CLI commands:
 ?                                  -- Display CLI Command List
 i                                  -- Display task information
 add remoteWbr                      -- Add a remote Wireless Bridge
 admin                              -- Temporary factory admin
 boot flash                         -- Boot from flash
 boot ethernet                      -- Boot from network
 cp                                 -- Copy file
 config wlan                        -- config wlanX
 config virtualap                   -- config virtual ap
 config bss                         -- config bss
 connect bss                        -- connect to bssX
 del acl                            -- Delete Access Control List
 del key                            -- Delete Encryption key
 del remoteWbr                      -- Delete a remote Wireless Bridge
 find bss                           -- Find BSS
 find bssPassive                    -- Find BSS with passive scans
 find channel                       -- Find Available Channel
 find all                           -- Find All BSS
 format                             -- Format flash filesytem
 MFT_Ant                            -- Setting Antenna Status
 MFT_Boot_Ver                       -- MFT Show boot code version .
 MFT_Led                            -- MFT Setting Led Traffic Rate .
 MFT_Show_Boot                      -- Show boot up message
 start_tr                           -- start traffic rate monitor
 stop_tr                            -- stop traffic rate monitor
 bootrom                            -- Update boot rom image
 ftp                                -- Software update via FTP
 get 11gonly                        -- Display 11g Only Allowed
 get 11goptimize                    -- Display 11g Optimization Level
 get 11goverlapbss                  -- Display Overlapping BSS Protection
 get abolt                          --
 get acl                            -- Display Access Control List
 get aging                          -- Display Aging Interval
 get antenna                        -- Display Antenna Diversity
 get arptable                       -- Display ARP Table
 get route                          -- Display Route Table
 get association                    -- Display Association Table
 get authentication                 -- Display Authentication Type
 get autochannelselect              -- Display Auto Channel Select
 get basic11b                       -- Display Basic 11b Rates
 get basic11g                       -- Display Basic 11g Rates
 get beaconinterval                 -- Display Beacon Interval
 get bootLine                       -- Display the bootLine
 get burstSeqThreshold              -- Display Max Number of frames in a Burst
 get burstTime                      -- Display Burst Time
 get cacheperf                      -- Display the cache performance counters
 get calibration                    -- Display Noise And Offset Calibration Mode
 get cckTrigHigh                    -- Display Higher Trigger Threshold for CCK Phy Errors for ANI Control
 get cckTrigLow                     -- Display Lower Trigger Threshold for CCK Phy Errors for ANI Control
 get cckWeakSigThr                  -- Display ANI Parameter for CCK Weak Signal Detection Threshold
 get channel                        -- Display Radio Channel
 get cipher                         -- Display Encryption cipher
 get compproc                       -- Display Compression scheme
 get compwinsize                    -- Display Compression Window Size
 get config                         -- Display Current AP Configuration
 get countrycode                    -- Display Country Code
 get cpu                            -- Display CPU Loading
 get radarnewchannel                -- Display radar new channel
 get csabeaconcount                 -- Display CSA Beacon Count
 get ctsmode                        -- Display CTS mode
 get ctsrate                        -- Display CTS rate
 get ctstype                        -- Display CTS type
 get domainsuffix                   -- Display Domain Name Server suffix
 get dtim                           -- Display Data Beacon Rate (DTIM)
 get enableANI                      -- Display Adaptive Noise Immunity Control On/Off
 get encryption                     -- Display Encryption Mode
 get extendedchanmode               -- Display Extended Channel Mode
 get firStepLvl                     -- Display ANI Parameter for FirStepLevel
 get fragmentthreshold              -- Display Fragment Threshold
 get frequency                      -- Display Radio Frequency (MHz)
 get gateway                        -- Display Gateway IP Address
 get gbeaconrate                    -- Display 11g Beacon Rate
 get gdraft5                        -- Display 11g Draft 5.0 compatibility
 get groupkeyupdate                 -- Display Group Key Update Interval (in Seconds)
 get hardware                       -- Display Hardware Revisions
 get hostipaddr                     -- Display Host IP Address
 get information                    -- Display Manufacture Information
 get interVF                        -- Display Inter Vap Forwarding State
 get intraVF                        -- Display Intra Vap Forwarding State
 get ipaddr                         -- Display IP Address
 get ipmask                         -- Display IP Subnet Mask
 get jsw                            -- Display Jumpstart Mode
 get jsP2PassPhrase                 -- Display JS-P2 passphrase
 get key                            -- Display Encryption Key
 get keyentrymethod                 -- Display Encyrption Key Entry Method
 get keysource                      -- Display Source Of Encryption Keys
 get login                          -- Display Login User Name
 get minimumrate                    -- Display Minimum Rate
 get nameaddr                       -- Display IP address of name server
 get nf                             -- Display Noise Floor
 get noiseImmunityLvl               -- Display ANI Parameter for Noise Immunity Level
 get ofdmTrigHigh                   -- Display Higher Trigger Threshold for OFDM Phy Errors for ANI Control
 get ofdmTrigLow                    -- Display Lower Trigger Threshold for OFDM Phy Errors for ANI Control
 get ofdmWeakSigDet                 -- Display ANI Parameter for OFDM Weak Signal Detection
 get overRidetxpower                -- Display Tx power override
 get operationMode                  -- Display Operation Mode
 get pktLogEnable                   -- Display Packet Logging Mode
 get power                          -- Display Transmit Power Setting
 get pppoe                          -- display the PPPoE setting
 get pppoeInfo                      -- display the PPPoE setting
 get pvid                           -- Display the VLAN Tag
 get quietAckCtsAllow               -- Display if Ack/Cts frames are allowed during quiet period
 get quietDuration                  -- Display Duration of quiet period
 get quietOffset                    -- Display Offset of quiet period into the beacon period
 get radiusname                     -- Display RADIUS server name or IP address
 get radiusport                     -- Display RADIUS port number
 get rate                           -- Display Data Rate
 get reg                            -- Display the register contents at the given offset
 get telecregstatus                 -- Display Telec 5GHz Regulatory Update status
 get remoteAp                       -- Display Remote Ap's Mac Address
 get reset                          -- Display # of resets
 get remoteWbr                      -- Display configured Remote Wireless bridges
 get hwtxretries                    -- Display HW Transmit Retry Limit
 get swtxretries                    -- Display SW Transmit Retry Limit
 get rogueAPDetect                  -- Display Rogue AP Detection Mode
 get bkScaninterval                 -- Display Background Scan Interval for Rogue AP detection
 get rtsthreshold                   -- Display RTS/CTS Threshold
 get shortpreamble                  -- Display Short Preamble Usage
 get shortslottime                  -- Display Short Slot Time Usage
 get snmp                           -- Display SNMP Community Name
 get sntpserver                     -- Display SNTP/NTP Server IP Address
 get softwareretry                  -- Display Software Retry
 get spurImmunityLvl                -- Display ANI Parameter for Spur Immunity Level
 get ssid                           -- Display Service Set ID
 get ssidsuppress                   -- Display SSID Suppress Mode
 get active                         -- Display Active (up) Mode
 get station                        -- Display Station Status
 get SuperG                         -- Display SuperG Feature Status
 get systemname                     -- Display Access Point System Name
 get telnet                         -- Display Telnet Mode
 get timeout                        -- Display Telnet Timeout
 get tzone                          -- Display Time Zone Setting
 get updateparam                    -- Display Vendor Default Firmware Update Params
 get upsd                           -- Display UPSD Mode
 get uptime                         -- Display UpTime
 get vaps                           -- Display Number of Virtual APs
 get vlan                           -- Display VLAN Operational State
 get qos                            -- Display QoS Mode
 get watchdog                       -- Display Watchdog Mode
 get wds                            -- Display WDS Mode
 get wep                            -- Display Encryption Mode
 get wirelessmode                   -- Display Wireless LAN Mode
 get wmm                            -- Display WMM Mode
 get wmmParamBss                    -- Display WMM parameters used by STA in this BSS
 get wmmParam                       -- Display WMM parameters used by this AP
 get usrp                           -- Display the User Priority
 get wlanstate                      -- Display wlan state
 get xrpoll                         -- Display XR poll
 get xrbss                          -- Display XR Bss Info
 get xrFragmentThreshold            -- Display XR fragment threshold
 get mtu                            -- Display ppp MTU
 help                               -- Display CLI Command List
 Lebradeb                           -- Disable reboot during radar detection
 ls                                 -- list directory
 mem                                -- system memory statistics
 mv                                 -- Move file
 netpool                            -- Display Netpool usage
 np                                 -- Network Performance
 ns                                 -- Network Performance Server
 ping                               -- Ping
 pktLog                             -- Packet Log
 radar!                             -- Simulate radar detection on current channel
 reboot                             -- Reboot Access Point
 rm                                 -- Remove file
 run                                -- Run command file
 quit                               -- Logoff
 set 11gonly                        -- Set 11g Only Allowed
 set 11goptimize                    -- Set 11g Optimization Level
 set 11goverlapbss                  -- Set Overlapping BSS Protection
 set abolt                          --
 set acl                            -- Set Access Control List
 set aging                          -- Set Aging Interval
 set antenna                        -- Set Antenna
 set authentication                 -- Set Authentication Type
 set autochannelselect              -- Set Auto Channel Selection
 set basic11b                       -- Set Use of Basic 11b Rates
 set basic11g                       -- Set Use of Basic 11g Rates
 set beaconinterval                 -- Modify Beacon Interval
 set bkScaninterval                 -- Modify Background Scan Interval for Rogue AP Detection
 set board                          -- Set the board data
 set bootLine                       -- Change the bootline
 set burstSeqThreshold              -- Set Max Number of frames in a Burst
 set burstTime                      -- Set Burst Time
 set cachePerf                      -- Begin cache performance monitoring
 set calibration                    -- Set Calibration Period
 set cckTrigHigh                    -- Set Higher Trigger Threshold for CCK Phy Errors For ANI Control
 set cckTrigLow                     -- Set Lower Trigger Threshold for CCK Phy Errors For ANI Control
 set cckWeakSigThr                  -- Set ANI Parameter for CCK Weak Signal Detection Threshold
 set channel                        -- Set Radio Channel
 set cipher                         -- Set Cipher
 set compproc                       -- Set Compression Scheme
 set compwinsize                    -- Set Compression Window Size
 set consolelog                     -- Set Console Log Enable Disable
 set countrycode                    -- Set Country Code
 set radarnewchannel                -- Set radar new channel
 set csabeaconcount                 -- Set CSA Beacon Count
 set ctsmode                        -- Set CTS Mode
 set ctsrate                        -- Set CTS Rate
 set ctstype                        -- Set CTS Type
 set domainsuffix                   -- Set Domain Name Server Suffix
 set dtim                           -- Set Data Beacon Rate (DTIM)
 set enableANI                      -- Turn Adaptive Noise Immunity Control On/Off
 set encryption                     -- Set Encryption Mode
 set extendedchanmode               -- Set Extended Channel Mode
 set factorydefault                 -- Restore to Default Factory Settings
 set firStepLvl                     -- Set ANI Parameter for FirStepLevel
 set fragmentthreshold              -- Set Fragment Threshold
 set frequency                      -- Set Radio Frequency (MHz)
 set gateway                        -- Set Gateway IP Address
 set gbeaconrate                    -- Set 11g Beacon Rate
 set groupkeyupdate                 -- Set Group Key Update Interval (in Seconds)
 set gdraft5                        -- Set 11g Draft 5.0 compatibility
 set getsnmp                        -- Modify Get SNMP Community Name
 set hostipaddr                     -- Set Host IP address
 set interVF                        -- Set Inter Vap Forwarding State
 set intraVF                        -- Set Intra Vap Forwarding State
 set ipaddr                         -- Set IP Address
 set ipmask                         -- Set IP Subnet Mask
 set jsw                            -- Set Jumpstart Mode
 set jsp2Passwd                     -- Set JS-P2 password
 set key                            -- Set Encryption Key
 set keyentrymethod                 -- Select Encryption Key Entry Method
 set keysource                      -- Select Source Of Encryption Keys
 set login                          -- Modify Login User Name
 set minimumrate                    -- Set Minimum Rate
 set minimumrate                    -- Set Minimum Rate
 set minimumrate                    -- Set Minimum Rate
 set minimumrate                    -- Set Minimum Rate
 set minimumrate                    -- Set Minimum Rate
 set nameaddress                    -- Set Name Server IP address
 set noiseImmunityLvl               -- Set ANI Parameter for Noise Immunity Level
 set ofdmTrigHigh                   -- Set Higher Trigger Threshold for OFDM Phy Errors for ANI Control
 set ofdmTrigLow                    -- Set Lower Trigger Threshold for OFDM Phy Errors for ANI Control
 set ofdmWeakSigDet                 -- Set ANI Parameter for OFDM Weak Signal Detection
 set overRidetxpower                -- Set Tx power override
 set operationMode                  -- Set operation Mode
 set password                       -- Modify Password
 set passphrase                     -- Modify Passphrase
 set pktLogEnable                   -- Enable Packet Logging
 set power                          -- Set Transmit Power
 set pppoe                          -- Enable the PPPoE
 set pppoePassword                  -- Set the PPPoE password
 set pppoeUsername                  -- Set the PPPoE username
 set pvid                           -- Set the VLAN Tag
 set quietAckCtsAllow               -- Allow Ack/Cts frames during quiet period
 set quietDuration                  -- Duration of quiet period
 set quietOffset                    -- Offset of quiet period into the beacon period
 set radiusname                     -- Set RADIUS name or IP address
 set radiusport                     -- Set RADIUS port number
 set radiussecret                   -- Set RADIUS shared secret
 set rate                           -- Set Data Rate
 set rate                           -- Set Data Rate
 set rate                           -- Set Data Rate
 set rate                           -- Set Data Rate
 set rate                           -- Set Data Rate
 set reg                            -- Set Register Value
 set telecregupdate                 -- Perform Telec Regulatory Update
 set telecregupdatereverse          -- Perform Reverse of Telec Regulatory Update
 set regcapbitswrite                -- Write Regulatory Domain Capability bits to EEPROM
 set regulatorydomain               -- Set Regulatory Domain
 set remoteAP                       -- Set Remote AP's Mac Address
 set hwtxretries                    -- Set HW Transmit Retry Limit
 set swtxretries                    -- Set SW Transmit Retry Limit
 set rogueAPDetect                  -- Set Rogue AP Detection Mode
 set rtsthreshold                   -- Set RTS/CTS Threshold
 set shortpreamble                  -- Set Short Preamble
 set shortslottime                  -- Set Short Slot Time
 set setsnmp                        -- Modify Set SNMP Community Name
 set sntpserver                     -- Set SNTP/NTP Server IP Address
 set softwareretry                  -- Set Software Retry
 set spurImmunityLvl                -- Set ANI Parameter for Spur Immunity Level
 set ssid                           -- Set Service Set ID
 set ssidsuppress                   -- Set SSID Suppress Mode
 set active                         -- Set Active (up) Mode
 set station                        -- Set Station Skype Authentication
 set SuperG                         -- Super G Features
 set systemname                     -- Set Access Point System Name
 set telnet                         -- Set Telnet Mode
 set timeout                        -- Set Telnet Timeout
 set tzone                          -- Set Time Zone Setting
 set updateparam                    -- Set Vendor Default Firmware Update Params
 set vaps                           -- Set Number of Virtual APs
 set upsd                           -- Set UPSD Mode
 set vlan                           -- Set VLAN Operational State
 set qos                            -- Set QoS Mode
 set watchdog                       -- Set Watchdog Mode
 set wds                            -- Set WDS Mode
 set wep                            -- Set Encryption Mode
 set wlanstate                      -- Set wlan state
 set wirelessmode                   -- Set Wireless LAN Mode
 set usrp                           -- Set the User Priority
 set wmm                            -- Set WMM Mode
 set wmmParamBss                    -- Set WMM parameters used by STAs in this BSS
 set wmmParam                       -- Set WMM parameters used by this AP
 set xr                             -- Set XR
 set nat                            -- Set NAT/DHCP Server
 set mtu                            -- Display ppp MTU
 spy report                         -- Print spy report
 spy start                          -- Start spy
 spy stop                           -- Stop spy
 start wlan                         -- Start the current wlan
 stop wlan                          -- Stop the current wlan
 timeofday                          -- Display Current Time of Day
 version                            -- Software version
 nat_tcp                            -- nat_tcp_show
 nat_udp                            -- nat_udp_show

I tried a few commands to get a feel for the device:

wlan[0,0] -> get information
Product SN  :  
AP Software : v1.0.6.0
MAC Address : 00-12-CF-80-46-2C
wlan[0,0] -> get updateparam
Vendor Default Update Parameters:
       Hostname:  
       Username:  
       Password:  
       Imagepath:
       Imagename:
       Flag:      0x0
wlan[0,0] -> ls
zz-img.bin  1350968
apcfg          6886
apcfg.bak      6885
2101248 bytes free
wlan[0,0] -> MFT_Boot_Ver
Boot code version is  1.1.0
wlan[0,0] -> bootrom
Not enough parameters!

It looked like there was a filesystem on the flash, containing the zz-img.bin firmware I originally started with, and another file called apcfg. Using the ‘ftp’ command I’d seen in ‘help’ I uploaded both of these files to an FTP server running on the Pi. The md5sum of the new zz-img.bin matched the firmware image I started with, while the apcfg was, as the name implies, a configuration file. It begins:

# DO NOT EDIT -- This configuration file is automatically generated
magic Ar52xxAP
fwc: 8
login Admin
nameaddr 8.8.8.8
domainsuffix
RADIUSaddr
RADIUSport 1812
RADIUSsecret
password 1988

(At some point, someone – probably me – must have configured it with Google’s Public DNS service running on the IP address 8.8.8.8)

As I belatedly found out, all of these commands work fine over the telnet interface that’s also running on the router. I should probably have tried that earlier, but I was particularly interested in gaining access to the bootloader on the router to see if I could persuade it to boot up a different firmware. Eager to see if that was possible, I typed ‘reboot’ and crossed my fingers:

wlan[0,0] -> reboot
0x80ed2750 (tCliTask): wlan0: vportBSSEndStop -- already stopped!
Rebooting AP...

ar531xPlus rev 0x00000086 firmware startup...


Accton boot code version 1.1.0


 4 3   00
auto-booting...

Attached TCP/IP interface to ae0.
Warning: no netmask specified.
Attaching network interface lo0... done.
Attaching to TFFS... Attaching to TFFS... done.
Loading /fl/zz-img.bin...Boot web up ...
1456176
Starting at 0x804846e0...

                                                    /fl/  - Volume is OK
Reading Configuration File "/fl/apcfg".
Configuration file checksum: 85c2c is good
Attaching interface lo0...done
wireless access point starting...
Auto Channel Scan selected 2412 MHz, channel 1
wlan0 Ready
Ready

Success! Hitting enter got me back to the login prompt, so that appeared to be the sum total of the bootup messages. Soft-rebooting the device like this (rather than powering it up with the Pi attached) was fortuitous as the router has the same bug as the Fonera; having something already connected to the serial interface when it’s powered on causes it to hang and produce no serial output.

Trying to interrupt the boot loader, after much trial and error I hit ‘Esc’ during what’s evidently supposed to be a countdown that appears just before the “auto-booting” message. That dropped me into what looked like a command prompt, so I tried ‘help’ again:

4
oot]: help

 ?                     - print this list
 @                     - boot (load and go)
 p                     - print boot params
 c                     - change boot params
 L                     - ACCTON MFT Led Test
 e                     - print fatal exception
 v                     - print version
 B                     - change board data
 S                     - show board data
 n netif               - print network interface device address
 $dev(0,procnum)host:/file h=# e=# b=# g=# u=usr [pw=passwd] f=#
                           tn=targetname s=script o=other
 boot device: tffs=drive,removable     file name: /tffs0/vxWorks
 Boot flags:          
   0x02  - load local system symbols
   0x04  - don't autoboot
   0x08  - quick autoboot (no countdown)
   0x20  - disable login security
   0x40  - use bootp to get boot parameters
   0x80  - use tftp to get boot image
   0x100 - use proxy arp

available boot devices:Enhanced Network Devices
 ae0 tffs

This is the standard VxWorks “BSP” bootloader, and the commands it lists works as advertised:

[Boot]: p

boot device          : tffs:
unit number          : 0
processor number     : 0
file name            : /fl/zz-img.bin
inet on ethernet (e) : 192.168.1.240:0xffffff00
flags (f)            : 0x0
other (o)            : ae

[Boot]: c

'.' = clear field;  '-' = go to previous field;  ^D = quit

boot device          : tffs:0
processor number     : 0
host name            :
file name            : /fl/zz-img.bin
inet on ethernet (e) : 192.168.1.240:0xffffff00
inet on backplane (b):
host inet (h)        :
gateway inet (g)     :
user (u)             :
ftp password (pw) (blank = use rsh):
flags (f)            : 0x0
target name (tn)     :
startup script (s)   :
other (o)            : ae

[Boot]: S
name:     SAP2315A-FLF-38FT
magic:    35333131
cksum:    a943
rev:      5
major:    1
minor:    0
pciid:    0013
wlan0:    yes 00:12:cf:80:46:2d
wlan1:    no  ff:ff:ff:ff:ff:ff
enet0:    yes 00:12:cf:80:46:2c
enet1:    no  ff:ff:ff:ff:ff:ff
localbus: no  ff:ff:ff:ff:ff:ff
PCI:      no  ff:ff:ff:ff:ff:ff
uart0:    yes
sysled:   no, gpio 0
factory:  yes, gpio 6
serclk:   internal
cpufreq:  calculated 184000000 Hz
sysfreq:  calculated 92000000 Hz
memcap:   disabled
watchdg:  enabled
product sn:          
country code:        NA
hardware rev:   R01
product name:        SAP2315A-FLF-38FT
hardware id:         0
manufacturing date:  20080205
Wireless Bridge is not supported
Boot code version : 1.1.0
[Boot]: v
CPU: SAP2315A-FLF-38FT
BSP version: 1.1.0
Creation date: Aug 17 2006, 19:47:11

I was pleased to see that loading a boot image over the network was supported. To try it, I used the ‘c’ command seen above to change the boot device to ae0, entered the IP address of the Pi, the path to its local copy of zz-img.bin and set the flags value to 0×80 (“use tftp to get boot image”).

Without that flag, the BSP would try to use ordinary FTP (as opposed to TFTP) which I encountered some issues with (“Error loading file: errno = 0xDD” 2). Being somewhat simpler, TFTP was easier to get working – I just installed acftpd on the Pi, verified from my laptop that I could download a file from it, then rebooted the router.

I was slightly surprised to see it work! Other than a slightly different “Loading” message, the router fetched its firmware from the Pi and booted up into it as normal. This told me two things, firstly that as long as I could still access the bootloader I had a potential way to recover the device from any meddling gone wrong, and secondly that BSP would fetch and execute an ELF image.

I’d noted earlier that all of the other routers in this family I could find reportedly ran Linux out of the box. It seemed that using the same RedBoot bootloader that they did would help get me towards my vague long-term goal for getting Linux going on this router too. It would also prove that I could run arbitrary code on the device.

RedBoot

Getting a copy of RedBoot for this router was an interesting learning experience – most people aren’t interested in an ELF executable of it, they want a stripped down ‘ROM’ version to flash directly to their device. I certainly wanted to make sure it would work before I thought about going that far, and not finding any suitable pre-built images, I decided to build my own. That would also help with the issue of the 250G’s flash memory size being different to that of the Fonera.

As the Fonera 2100 is so well known, there are plenty of logs out there of RedBoot booting on it. All of them contained the line “Board: ap51″ which was very helpful in helping me narrow down what I was looking for. That led me to Micro Redboot, which seemed to be almost exactly what I was looking for. Unfortunately I failed to get it to build – unfortunately the world, and particularly gcc, seems to have moved on in the years since most router RedBoot trees were last built, resulting in all sorts of incompatibilities and syntax errors when attempting to build them with a modern toolchain.

I wish I’d noticed this before spending the time I did on Micro Redboot, but knowing that the WAP250G was practically a clone of the Meraki Mini was very helpful, because they provide their source code, including the version of RedBoot they use. Building it turned out to be straightforward, as the file redboot-ap61.tar.gz – despite the ‘61’ in the name – can also be used to build an ap51 RedBoot, and even contains the i386 Linux toolchain needed to do so.

After unpacking that archive under Linux and examining the Makefile, building a customized RedBoot was almost as simple as typing:

$ make AP_TYPE=ap51 DRAM_MB=16 FLASH_MB=4 ENET_PHY=admtek ap51

Knowing the values to use for the RAM and flash size was straightforward, being identifiable from the markings on the chips themselves. The Ethernet PHY was harder, if only because I couldn’t see it on the board. Various Fonera-hacking websites told me it was an “Altima AC101″ (which is printed on a chip on the bottom of the board), but how that mapped to the choices I had (“admtek”, “marvell”, “realtek”, “icplus” or “kendin”) I had no idea. So I tried the first one.

Of course, when I said building it was “almost as simple” as the command above, I hadn’t factored in the error that would appear partway through the build process:

tail: cannot open `+2' for reading: No such file or directory

That was caused by the use of some obsolete syntax (“tail +2″ should be “tail -n2″ since 2007 or so!) and could be corrected by setting the _POSIX2_VERSION variable in the environment before running make:

$ _POSIX2_VERSION=199209 make TFTPPATH=~/tftpboot AP_TYPE=ap51 DRAM_MB=16 FLASH_MB=4 ENET_PHY=icplus ap51

I set the TFTPPATH variable to somewhere under my home directory (rather than the default /tftpboot) so I’d have permission to write to it. After typing the above, and a few seconds of compilation, I now had two new files: ap51-4mb-16mb.ram and ap51-4mb-16mb.ram. The former is the ELF image I needed.

$ ls -l ~/tftpboot/
total 752
-rwxr-xr-x 1 james james 601653 Nov 28 18:28 ap51-4mb-16mb.ram
-rwxr-xr-x 1 james james 158816 Nov 28 18:28 ap51-4mb-16mb.rom

The (relatively) huge size of the ELF (almost 600KB!) surprised me for a moment, but as file noted, the file wasn’t stripped of debugging symbols. The mipsisa32-elf-strip tool included in the toolchain made short work of those. I was left with a with a 152KB ELF, which I uploaded to the Pi and placed in the tftp directory. Switching back to minicom, I accessed the bootloader on the router and changed it to boot this new file, which was just a case of changing the filename as it was already set up to boot over TFTP. I then tried booting it up:

[Boot]: @
Attached TCP/IP interface to ae0.
Attaching network interface lo0... done.
Loading... 250448
Starting at 0x800410bc...

+**Warning** FLASH configuration checksum error or invalid key
Use 'fconfig -i' to [re]initialize database
Invalid PHY ID1 for enet0 port0.  Expected 0x0243, read 0x0022
... waiting for BOOTP information
Ethernet eth0: MAC address 00:12:cf:80:46:2c
Can't get BOOTP info for device!

RedBoot(tm) bootstrap and debug environment [RAM]
Non-certified release, version v1.3.0 - built 18:28:43, Nov 28 2012

Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

Board: ap51
RAM: 0x80000000-0x81000000, [0x8007e250-0x80fe1000] available
FLASH: 0xa8000000 - 0xa83f0000, 64 blocks of 0x00010000 bytes each.
RedBoot>

Wow. RedBoot loaded fine – though the “Invalid PHY ID1″ message told me that I’d guessed wrong when choosing the PHY earlier. The “Expected 0×0243, read 0×0022″ detail was extremely useful though – buried in the RedBoot source, in a file called rtPhy.h I found this:

#define RT_PHY_ID1_EXPECTATION  0x22

which contained the comment:

/*
 * rtPhy.h - definitions for the ethernet PHY.
 * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
 * and compatible PHYs, such as the Kendin KS8721B.
 * All definitions in this file are operating system independent!
 */

That looked promising, so I tried rebuilding RedBoot with the ENET_PHY value set to ‘realtek’. Unfortunately, an unsatisfied constraint – that on the AR531X platform the PHY could be any of the types I listed except ‘realtek’ (typical) – caused the build to fail. The helpful comment above led me to try ‘kendin’ instead, and that both built and booted fine:

+**Warning** FLASH configuration checksum error or invalid key
Use 'fconfig -i' to [re]initialize database
PHY ID is 0022:5521
... waiting for BOOTP information
Ethernet eth0: MAC address 00:12:cf:80:46:2c
IP: 192.168.0.10/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1

RedBoot(tm) bootstrap and debug environment [RAM]
Non-certified release, version v1.3.0 - built 18:48:12, Nov 28 2012

Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

Board: ap51
RAM: 0x80000000-0x81000000, [0x8007d6f0-0x80fe1000] available
FLASH: 0xa8000000 - 0xa83f0000, 64 blocks of 0x00010000 bytes each.
RedBoot> bdshow
name:     SAP2315A-FLF-38FT
magic:    35333131
cksum:    a943
rev:      5
major:    1
minor:    0
pciid:    0013
wlan0:    yes 00:12:cf:80:46:2d
wlan1:    no  ff:ff:ff:ff:ff:ff
enet0:    yes 00:12:cf:80:46:2c
enet1:    no  ff:ff:ff:ff:ff:ff
uart0:    yes
sysled:   no, gpio 0
factory:  yes, gpio 6
serclk:   internal
cpufreq:  calculated 184000000 Hz
sysfreq:  calculated 92000000 Hz
memcap:   disabled
watchdg:  enabled
serialNo: <Not a string: 0xA83E007C>
Watchdog Gpio pin: 65535
secret number: <Not a string: 0xA83E008A>

It even set an IP address over BOOTP, so the network interface was clearly working.

RedBoot’s ‘help’ output is well known, so I won’t paste it here, but one of the reasons I wanted to run it in the first place was this command:

Display (hex dump) a range of memory
   x -b <location> [-l <length>] [-s] [-1|2|4]

The RedBoot startup banner lists RAM and FLASH memory locations and sizes, so I speculated that I could use that command to dump their contents over the serial interface. After making sure minicom was logging everything to disk (or rather the SD card on the Pi), I dumped the flash contents like so:

RedBoot> dump -b 0xa8000000 -l 0x3f0000
A8000000: 10 00 01 4F 00 00 00 00 10 00 02 04 00 00 00 00 |...O............|
A8000010: 10 00 06 78 00 00 00 00 10 00 06 76 00 00 00 00 |...x.......v....|
A8000020: 10 00 06 74 00 00 00 00 10 00 06 72 00 00 00 00 |...t.......r....|
A8000030: 10 00 06 70 00 00 00 00 10 00 06 6E 00 00 00 00 |...p.......n....|
...

(I’ve altered the spacing slightly to get it to fit neatly.)

The actual output was of course 258,048 (0x3F0000) lines long, and I wish I’d thought to increase the baud rate before typing the command, as it took several hours to complete over the 9600 baud connection!

A couple of lines of Python code was sufficient to turn the dumped output into a binary image of the flash contents, exactly 4MB in length. I was conscious that dumping 20MB (before conversion) of hex dump over a bodged-together serial connection with no handshaking might not be very reliable, but luckily there was another RedBoot command to help:

Compute a 32bit checksum [POSIX algorithm] for a range of memory
   cksum -b <location> -l <length>

Handily, it accepts the same parameters as the ‘dump’ command, and I used it to calculate a checksum of the flash contents:

RedBoot> cksum -b 0xa8000000 -l 0x3f0000
POSIX cksum = 3466121872 4128768 (0xce98d290 0x003f0000)

I was momentarily dismayed though when the CRC32 of my dumped binary didn’t match that value, but looking at the above again I started wondering what exactly the “POSIX algorithm” was referring to. As I had the source code to hand I could find out easily, and in the process of looking at posix_crc.c in the RedBoot source, found what’s probably the most useful source code comment I have ever read:

// Compute a CRC, using the POSIX 1003 definition

// Same basic algorithm as CRC-16, but the bits are defined in the
// opposite order.  This computation matches the output of the
// Linux 'cksum' program.

Well, that’s handy. Sure enough:

$ cksum rom.bin
3466121872 4128768 rom.bin

At this point I was fairly sure that I had an accurate dump of the entire flash contents from the router. Even if I break the bootloader somehow, I can hopefully find a way to re-flash that image back to the chip, either via a JTAG cable or by physically de-soldering it from the board, if it came to that. Having said that, if it did come to that, I’d probably just put an 8MB chip in its place and flash it with the dump from a Fonera 2100 or a Meraki Mini.

From a reverse engineering perspective, the dumped data turns out to be reasonably interesting. Presumably for wear levelling purposes, slightly changed copies of the apcfg file are spread out fairly evenly over the flash, including details of all of the SSIDs this router has previously been configured with.

Next, I’ll probably use RedBoot to flash itself directly to the device, using the ‘fis’ commands it provides. ‘fis list’ shows what looks like garbage at the moment:

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
AP2315A-FLF-38FT  0x00FFFFFF  0x00323030  0x38303230  0x35000031
<Not a string: 0x80FF0000>                 0x2D464C46  0x2D333846  0x54006566  0x61756C74

I assume that’s due to the flash block it would use to store that information being used by VxWorks for a different purpose. ‘fis create’ would probably fix that, but I’d like to be more sure before I try!

Once RedBoot is permanently on the device, I’ll use it to boot Linux, either DD-WRT or OpenWRT most likely; first over the network and once I’m satisfied it works as expected, directly from flash. Longer term I’ll probably perform the Fonera SD card mod, and I have a vague idea about using the router as an I²C or SPI controller interfaced to some LED lighting strips.

Final Notes (TL;DR)

I now know that almost everything here could have been performed over the telnet connection without opening the device up at all; the ‘boot ethernet’ command can be used to instruct the bootloader to load an image over the network. The change persists between reboots, though holding down the reset button can be used to reset the unit to factory defaults and hence boot again from flash. That could be used to recover from failed attempts to network boot.

Likewise, RedBoot can be connected to over telnet once it has loaded, so in theory the whole process of re-flashing the device with a new bootloader and operating system could be done remotely. The procedure would take some refinement though.

During the research for this post, I found these instructions for flashing a D-Link DWL-2100AP over its serial console. They look very similar to what I was planning on doing to flash RedBoot to the WAP250G, the 2100AP is based on the same architecture and has the same RAM and flash size (though it’s not connected through SPI, so there are differences). If the 2100AP has a telnet accessible shell, and it has the ‘boot ethernet’ command, it should be possible to flash it to Linux without opening it up, too. According to that router’s official documentation [PDF] though, that command is missing. I think I might have one in a box somewhere, if I find it I’ll give it a try.

After dumping the flash contents, I did so for the RAM too. I booted VxWorks, then soft rebooted into RedBoot via the BSP bootloader in as few steps as I could. I didn’t bother checksumming it due to its volatile nature, but I was pleased to see that easily identifiable chunks of VxWorks code remained visible in the resulting 16MB file. I’ve not read about anyone using RedBoot to dump the entire RAM or ROM contents of a device before, so I think this technique has a certain novelty to it. I now have a firmware image, its decompressed contents and a partial memory dump from running code to investigate should I wish to do so further.

I enjoyed finding out more about what makes this little router tick, and hope to find something useful to do with it soon!

Notes:

  1. Other search engines are available.
  2. 0xDD is 221 in decimal, which rather suspiciously is the “Service closing control connection” FTP status code.