AirMobi iReceiver Preliminary Software Hacking

I recently discovered and purchased an inexpensive, unofficial WiFi-enabled AirPlay and DNLA audio receiver called the AirMobi iReceiver. I couldn’t find much information on the device, but for $12, I thought it was worth buying and trying.

It works reasonably well, but that’s not really why I bought it. I bought it with the intention of taking it apart and seeing what makes it tick. And now, having done that, I plan to hack it to run OpenWRT so I can secure it, customize it, and update the software.

IMG_9667

It is based on a Ralink RT5305T WiFi SoC which suggests to me that it is running linux, and probably has a serial console exposed via some test points on the mother board. I only found handful of candidates during my teardown. My guess was that the Tx and Rx lines were available on the unpopulated 4-pin header at the edge of the circuit board. From visual inspection I could tell that the second pin from the left was a ground pin. A little continuity probing with a multimeter suggested the first pin provided power, a fact confirmed when I check its voltage when I powered up the device.

I hooked a logic analyzer up to the other two pins to see which one toggled on and off at boot, but that was really overkill. I could have done just as well figuring out which one was pulled high when I powered up the device.

Once I had the pins worked out, I hooked up a TTL level USB/serial converter to my laptop, connected the ground pins and cross connected the Tx and Rx pins between the adapter and the board. Once I powered everything up, my screen started to fill with garbage. I guessed that 115.2Kbps was too fast, and tried 57.6Kbps instead. Bingo!

After booting up, I hit return and was presented with a login prompt. I tried the password for the webui and was pleased to find that it worked. I poked around the filesystem, looking at various config files, the various files for the web UI, and checking what binaries were installed on the system.

One of them is a telnet daemon (implemented as part of busybox). So, I started it, connected to the WiFi, and was able to log in over the network.

From there, I gathered more information. I was dissapointed that there wasn’t really anything like zip, or tar, or an ftp or ssh server that would make it easy to pull a bunch of files off at once, so I dumped the web UI files to the terminal one at a time and then saved them for further inspection.

Hidden ate_test.asp page

Hidden test_ate.asp page

Once I did, I found hidden functions in the firmware update page for uploading the bootloader over the webui. Exposing it required tweaking the page using web developer tools, which is kind of tedious. Then I hit the jackpot, I found an unlinked file called test_ate.asp. When loaded, it has a button to fire up the telnet daemon, making a command line available with just a WiFI connection, no serial console necessary. It also has an option to update the boot loader and a mysterious ATE function. This discovery made it easier to return and poke at the device at my leisure.

From what I learned in my poking and prodding, it appears to be based on the Ralink provided SDK with some modifications. With any luck, the modifications will be minor, and it will be easy to load an OpenWRT firmware over the webUI.

Before I do that though, I’ll need to take special care since this device doesn’t have an ethernet port, and so recovering from non-working firmware will be more difficult.

A lot of details follow…

Continue reading

AirMobi iReceiver Teardown

I’ve ended up with five small, inexpensive ($7-15 each) routers, running OpenWrt and only really need two of them, so I’ve been thinking of ways to use the others. One of my ideas was to get an external USB DAC, install Shairport-Sync, and use it as an AirPlay receiver for my car stereo, eliminating the need to connect an audio cable to my phone, and avoiding the mediocre sound quality of Bluetooth audio. It hasn’t quite worked out that way though…

While looking for an inexpensive (>$20), compact USB DAC with reasonable quality, I discovered there were integrated commercial products that already do what I planned to do. I already knew there were Apple-approved MFi-certified devices, but they tended to be expensive. I discovered there were cheaper devices using Shairport, but they tended to start at $30+.

Damaged while trying to open the case.

Damaged while trying to open the case.

With a little more digging though, I found a device called the iReceiver, from AirMobi that sells for as little as $12!!!. According to the scant marketing materials, it has a 24-bit Wolfson DAC. I was surprised I couldn’t find anyone who’d opened one up to see what was inside. I did find an Amazon review from someone complaining that the usb power connector had broken off on theirs, and the included photo showed it had a Ralink RT5350F WiFi SoC, which gave me hope that it would be hackable. So, I bought one.

Before opening it up, I tried it out. It works as promised. It defaults to broadcasting an unsecured WiFi network. Once connected, it shows up as an AirPlay receiver in iTunes, etc. From there, you can connect it to some powered speakers, select it and start playing music. The audio quality doesn’t suck (no obvious noise, clipping, or distortion), and in my limited use, there were fewer dropouts that I’m used to with Bluetooth.

Beyond that, there are various configuration options available through a browser based interface. There are no audio-related settings at all. Most of the settings are networking related. You can rename and secure the WiFi network with a password (good), WPS (bad) and by limited connections to specific devices by MAC address (meh). You can also connect to an existing network (good), and, optionally, extend it (meh). This seems like a good point to mention that it also works as a DNLA “renderer” (DNLA is a more open standard than AirPlay, making this useful to Windows and Linux devices, and Android phones with an appropriate app)

Of course, I didn’t buy it to use it with the stock firmware, so after trying it out, I opened it up to take a look inside. In the process, I managed to tear the translucent plastic that was affixed to the top of the case with adhesive. With the trim removed, it was easy to pry off the top, revealing the single PCB inside.

Version 2

As I expected, it is based on the obsolete but inexpensive and popular Ralink RT5350F WiFi SoC which includes a CPU and 802.11n WiFi.

  • Marked “RT5350F, TP08P40609, 1408STA”
  • 360MHz MIPS 24KEc CPU
  • 802.11n 1T/1R (1×1:1) 2.4 GHz 150Mbps MAC/BB/PA/RF
  • 5-port 10/100 Mbps Ethernet switch w/ 5 10/100 PHYs (unused)
  • USB 2.0 host/client (unused)

This is complimented by a modest, but sufficient 32MB of RAM and 8MB of flash memory to hold the firmware.

  • RAM
    • Marked: “EtronTech EM63A165TS-6G”
    • 255Mbit 16Mx16 5, 6, 7ns 166MHz SDRAM
  • Flash
    • Marked: “MXIC MX, 25L6406E, M2I-12G, 30392500, K141983”
    • Macronix MX25L6406E
    • 64Mbit NOR Flash
    • 4KB sector, 64KB block, 2.7-3.6v, H/W Hold
    • 1 or 2 bit bus, 86MHz x1 bus, 80MHz x2

The other major component is a Wolfson WM8960 CODEC to provide the audio output. This chip debuted in 2006, and includes 24-bit stereo DAC and ADC converters supporting sample rates up to 48Khz, a 40mW headphone driver, and a 1W Class D speaker driver.

Despite being a 24-bit DAC, the specified SnR of 98dBS matches that of the 16-bit TI/Burr Brown PCM2705 DAC used in the original AirportExpress, rather than of a modern, premium 24-bit DAC used in more recent AirportExpress’s. Oh well. Good enough for my purposes. Most of what I’m playing is compressed AAC files derived from 16-bit sources, and, AirPlay only passes 16-bit anyway. Beyond that, the design of the rest of the circuitry matters, and I’m not qualified to analyze it, nor am I equipped or inclined to try and measure it.

Beyond that, I see two inductors on the board (one of which is cracked). My guess is that these are part of some small switch mode power supplies, perhaps one for the digital section, and the other for the analog. There are two small LEDs to indicate device status and two momentary switches, one to reset the device, and the other to trigger WPS. It looks like it uses a single ceramic chip antenna for the WiFi.

There are a few unused pads for components, eight test points (half seemingly to do with power) and four unused holes for pin headers that I suspect provide a serial console.

That’s really it for the hardware. I’ve already started poking more deeply into the software and investigating the suspected serial console, and I hope to have another post soon documenting what I found.

IMG_9679

iReceiver Elsewhere

DIY Downsides: When successful troubleshooting deprives you of an excuse for upgrading.

The same base urges that led me to upgrade my home server, have had me itching to upgrade my home network. The server build sated that hunger for a while, but now that it is done, I’ve been feeling the pull, again. I’ve held out, but yesterday, I thought I was going to HAVE to upgrade because one of my routers started acting up. Happily/sadly, successful troubleshooting has stimied such rationalizations.

The current network arrangement consists of a Netgear WNDR3800 running OpenWRT as the main router/firewall. It has direct connections a couple of small ARM servers running Debian, which run various services. It also provides WiFi access. At the other side of the house, there is another router, a Netgear WNDR3700, also running OpenWRT that is bridged to the main router over 5GHz WiFi. It provides wired connectivity for a printer, a server, and a Acu-Link bridge that connects a weather station to the Internet. It also provides WiFi access in the 2.4GHz band and guarantees decent connectivity from our back yard.

I’ve been considering various options for upgrading, with the goals of getting a higher-speed link between the two routers, and a speed bump for my laptop, which has a 3-stream radio, whereas the routers are limited to two streams. I wasn’t entirely happy with any of the options though, which is one of the reasons I’d been able to resist the upgrade urge.

Yesterday though, as I’ve already mentioned, things started getting flakey. I noticed that the second router seemed to be rebooting every ten to fifteen minutes, interrupting connectivity for connected devices for a good 60-90 seconds. I could have used this as an excuse to upgrade, but I tried to troubleshoot the problem first.

I’d recently moved some equipment around, so the first thing I checked was that the power cord hadn’t been partially unplugged. It didn’t seem like it had, but I made sure it was well plugged in and waited to see if the problem continued. It did.

As part of the equipment moves, I’d swapped in a higher-capacity UPS. The UPS had been functioning just fine, in its previous location, but I wondered if it was adding noise that the routers power supply was having trouble contending with, so I swapped in another 12V DC wall wart. At first, that seemed to solve the problem, no reboots in over 20 minutes, but before another 20 minutes were over, the router rebooted again.

I wondered if it was a temperature issue. It was a warm day, though no warmer than other days this summer. I decided to take the router apart to see if there was any dust slowing down convection from the case. Once I got the case open though, I realized that I’d already opened and cleaned out the router a few weeks before. Back to the drawing board.

I decided to open up an SSH session so I could watch the system log (OpenWRT logs to a ring buffer in memory, so you have to use “logread -f.” in the hopes that I’d see something useful before the device rebooted itself. Once I had that running, I took my dog for a ~60 minute walk. When I returned, the router was still running, still logging to my screen. I scrolled back over the logs, and didn’t see anything unusual. I started to wonder if it was a “heisenbug.” Perhaps I was going to have to upgrade after all.

The log filled with information about connections and disconnections from WiFi devices, and IPv6 related housekeeping. A few minutes later though, something different flashed past on the console. I scrolled back and saw that the kernel reported that it detected a low memory condition and killed off a maintenance script to keep from running out of memory. I thought it strange, but I didn’t see what would have changed to make low-memory conditions commonplace, or how they’d lead to a reboot. It was, however, my only lead, and as I sat there thinking it over, I saw another low memory warning.

It was starting to make sense, I imagined how the router could get in a situation where it killed off an essential process and ended up rebooting. It might even be that the router hardware had a watchdog function, which would reboot the device if a process didn’t reset the watchdog timer on a regular interval. Killing that process could lead to a reboot.

Now that my only lead was starting to seem plausible, I dug deeper. I first checked the amount of memory in use with the “free” command. It reported there were less than 2MB free, which surprised me since I remembered it was typically many times that. Next I used “ps” to see what processes were running, and which were using the most memory. None of them were obviously huge, but a few of the larger processes didn’t look quite right.

I have an Acu-Rite weatherstation and an Acu-Link bridge. The bridge relays readings from the weatherstation to Acu-Rite’s servers. I have a system in place to capture the data as it is being transmitted, and feed it to Weewx on one of my servers. Weewx keeps its own record, and also updates Weather Underground. To accomplish this, I have a startup script on the secondary router that uses “ncat” to wait from an incoming connection from the driver I wrote for WeeWX. Once the connection comes in, ngrep sniffs for packets from the Acu-Link bridge relaying data from my weather station to the internet service. That data forwarded overmy network to the waiting weewx driver on my server.

The problem was that there were 3-4 copies of these processes running on the router. Ordinarily, there should only be one. After a connection is lost temporarily and weewx has reconnected, there might be two running before the old copy times out. I tried reducing the max number of connections from four to two, which helped a bit, but it was still cycling the connection much to quickly and for no obvious reason.

I tried restarting weewx, but that didn’t help, it was still connecting and then disconnecting too frequently. To debug things further, I decided to simulate the server connection and see if the data was being captured and forwarded properly. It wasn’t!

From here, I wanted to connect to the diagnostic webserver running on the Acu-Link to confirm that it had a connection to the weather station. I looked at the main router to find the Acu-Link’s IP address, and in the process I realized that it had changed. I hadn’t created a DHCP reservation for the Acu-Link device because DNSMasq, which provides DHCP service on the router, generally provides a stable IP address to devices. Something had happened though, probably when I was moving around hardware, and it had assigned a new IP address.

So, to recap:

  1. My script was depending on a result of the default behavior of DNSMasq for the IP address of the Acu-Link bridge.
  2. As a result of reconfiguring my network, something changed, and with it the result of that default behavior, leading to the IP address of the Acu-Link bridge changing.
  3. As a result, of the changed IP address, my script for sniffing weather data failed to collect that data and forward it to weewx running on my server.
  4. Because it wasn’t getting data as expected, weewx tried to reconnect to the sniffer script.
  5. Because weewx was reconnecting as frequently as it was, excess copies of ncat, ngrep and the ash shell accumulated on the router, eating up memory.
  6. Because of the low memory condition, the kernels out of memory killer (OOM killer) started killing off processes.
  7. Because some key process was killed by the OOM killer, the router rebooted, continuing the cycle.
  8. Because the router was rebooting frequently, I decided to troubleshoot it.
  9. Because I succeeded in troubleshooting the root cause, I have removed a reason to buy a new router.

Sometimes being awesome has to be its own reward, I guess.

Since I couldn’t in good conscience buy a new router, I did a few easy things to fix the problem. I configured the DHCP server to assign a predefined IP to the Acu-Link bridge, and update the script to look for packets from that IP.

There additional mediations to this issue that I probably won’t undertake, including:

  1. Updating my WeeWX driver to make sure it properly cleans up sockets when reconnecting. This might lead to quicker cleanup of the old processes on the router.
  2. Updating my WeeWX driver to throttle the rate at which it retries connections.
  3. Trying to automatically detect the IP of the Acu-Link bridge and then use that IP for the ongoing packet sniffing.
  4. Adding some code to the sniffer script that will be more aggressive about cleaning up unused connections.