Google OnHub Hacking

2023/07/31

I found these routers quite by accident, after I got a collection of Google Wifi pucks for very cheap and decided to look into their other Wi-fi products to see if they were able to be hacking and worth it to do so. And oh boy, did I find a doozy in the Onhub, which is branded as both TP-Link (TGR1900) and ASUS (SRT-AC1900) and made for Google Home. This article was written using TP-Link units, but it’s my understanding that the Asus model is very similar.

This was Google’s first Wi-fi offering, and it really seems like they didn’t know what they wanted to do with it, and fumbled it very badly as a result. They built in all sorts of superfluous hardware without really having a concrete reason for it out of the gate; bells and whistles like Bluetooth, a 3W speaker, a USB port, an RGB LED ring, a Zigbee chip, and some of the more overkill specs I’ve seen on a non-x86 router - it’s based on IPQ8064 SoC, a dual core 1.4ghz ARM CPU with two more 700mhz “Krait” network coprocessor cores, and comes coupled with a goddamn whole gigabyte of RAM, for an MSRP of 200 dollars. They didn’t even really use most of that properly, if at all - from what I have heard, the BT and speaker were only used optionally while setting up, the USB port is recovery-only, and the Zigbee chip does nothing at all in the original firmware. Then, they dropped support for using them without making it a pain in the ass - you had to manage through the Google Home app, but it no longer allows you to change the configuration of Onhubs, just use them in their existing configuration.* This is only after like, what, 5-6 years? Even though it’s still more than capable of handling like 600mbps throughput over wifi, which is more than enough for most people’s connections, they decided to intentionally put people’s home networks in a fragile state that leaves them pretty much locked out from most of the configuration features. Great job, guys. You could have had a neat little smart speaker and general home automation hub, if you wanted to, but you didn’t develop it properly then kicked it out of your walled garden ASAP. I suppose Google is very good at squandering a product with good potential with stupid decisions, then declaring it dead by mandate just early enough to piss people off, though.

(*: This is intepreted from others’ rantings on the internet. I don’t know firsthand how the firmware was managed, or how they dropped support, just that they did. I flashed these things with OpenWRT as soon as I got them and haven’t really touched the stock firmware.)

Preaching about corporate stupidity aside, that support being dropped means they are very cheap to buy, and fortunately again, Google has something of a propensity for leaving the developer tools open, assuming that you’re willing to tear down your device somewhat to get to that. The Onhub is no exception. It’s just as well, too, as the underlying hardware is actually quite good still, if you don’t need Wifi 6 or anything like that.

Dev-mode is relatively easy, and well documented elsewhere so I’ll be brief. Take off the rubber foot. (It’ll leave lots of gummy residue from the adhesive. 91%+ isopropyl alcohol will cut the residue. 70% doesn’t work nearly as well.) Look for a silver hex screw among the screws. 1.5mm head, I believe. Remove it. Stick your hex key through until you hit something. Feel a click? That’s the button for dev-mode controls. It’s really tiny and kinda difficult to hit. To trigger it into dev-mode, unplug it from power, hold the recessed reset button near the ports, then plug in the power. Hold until it turns orange, then red. After this, when you let go of the reset button, go hit the developer mode button that the hex screw was covering. Purple LEDs means it worked, and you are now entering developer mode.

Now, whenever it boots up, it’ll flash purple for 10-15 seconds then beep twice. Yes, it does this every time it boots now - live with it. This beep is your cue for pressing the developer mode button, which will boot into any flash storage you have plugged into the USB port.

Depthcharge, the prissy queen of ChromeOS

The bootloader is Google’s own bootloader for ChromeOS, Depthcharge. Yes, this router runs ChromeOS as its stock firmware. I suppose it is the Google Linux, and it’s probably better suited than Android, but that just feels weird.

Depthcharge is a little.. unique. That is, annoying. Depthcharge needs a separate kernel partition under a certain size, 64mb for newer devices and possibly as low as 16mb for older ones - at least, the OpenWRT image has a 16mb kernel partition, and I’ve found reference to a git commit from google increasing the size to 64MB in searches. If your image doesn’t meet Depthcharge’s requirements, it just refuses to boot with very little helpful feedback - even on devices that have screens to display error messages. Pleasant, huh?

The ‘flashing’ process is described on the OpenWRT wiki. It can be a little annoying. You should be able to just dd the image onto the eMMC, but as the note in the directions says, sometimes it’ll refuse to boot that as well as refusing to boot USB media after an attempted flash. If that happens, you may need to reset from stock firmware, repeat the dev-mode trigger process, and then first dd if=/dev/zero of=/dev/mmcblk0 bs=1M before trying to put the image on. Just fucking nuke it from orbit. No idea what the root cause of the issue is, but this works for me and multiple other people. 🤷

Most of this bootloader and flashing advice also applies to the Google Wifi ‘pucks’ - models AC-1304 and NLS-1304 - except for the fact that you have to take off the entire bottom to access the dev mode button, and use a USB-OTG hub with power delivery to plug in a USB stick. Also, the dd parameters for flashing are slightly different because the size of the flash is slightly different. See the OWRT device page for that. I used one of the ultra-cheap USB-C-HDMI-USB-A hubs like this on mine. The dev-mode switch is labeled SW7 and it’s tiny. The Wifi pucks don’t have all the other fancy bits, though, except for the NLS- model, the earliest model by the looks of things, which retains the Zigbee chip that the Onhub has - for all the good that does you. This advice does NOT apply to the GJ2CQ model - it’s got a barrel jack and no broken out USB-C. I believe these were provided by Google Fiber as their ISP router, but I’m not certain on that. As far as I know, this one hasn’t been ‘rooted’ yet due to lack of easy or obvious access. If anyone knows how to flash the GJ2CQ with an alternate OS feel free to write in and I’ll add the info with proper credit.

Bluetooth

It’s connected via USB and supported by ath3k. Install (or build your image with) kmod-ath3k, and install bluez, etc (see diffconfig for full list). Use bluetooth as normal with command line utilities. Not much to say other than that since configuration is pretty specific to what you want to do, but I’ve included a stub later about getting the Onhub working as a BT speaker.

Speaker

It should be recognized by ALSA and also pulseaudio. Install pulseaudio and whatever other audio software. It’ll run pulse in system mode; that’s how OpenWRT configures it by default for reasons I don’t quite understand. As a test without further advanced configuration, copy over a .wav file and play it using $AUDIOPLAYER. Here’s how you can use pacmd/pactl, if you need to - for example, to turn the sink down to about 80% volume, since the top volume results in some distortion. Requires sudo or (presumably) doas:

Bluetooth speaker

This is a bit of a pain, I’ve not made it a completely smooth experience yet. Manually ssh-ing and running bluetoothctl is necessary, in order to confirm and trust the connection for every new device. Volume control on the source is also completely non-functional. Input is welcome on how to get this to behave better.

Forewarning - this has a significant effect on network performance when it’s in usage. It basically pins one of the cores to 100% while playing audio. In this case you can still get good enough throughput for general usage if you’re using the networking coprocessors (see below), but it’s not ideal.

Packages to install for BT & speaker functionality

kmod-ath3k
kmod-bluetooth
kmod-input-uinput
kmod-sound-core
kmod-ath3k
alsa-utils
mpg-123 (just for testing audio)
sbc
bluez-daemon
bluez-libs
bluez-utils
dbus
pulseaudio-daemon-avahi
pulseaudio-profiles
pulseaudio-tools

pulseaudio-daemon-avahi is especially important here - the base pulseaudio-daemon package will not do. It’s only indicated in the package’s description, but pulseaudio-daemon-avahi is also built with Bluetooth support, while the pulseaudio-daemon package is not. You don’t need to install both.

TODO: Configuration process to be added - I’m not even sure how I got it working quite yet and need to poke further at it.. sorry! For some resources to assist in this, see here (OpenWRT wiki) for OpenWRT specific caveats, as well as guides for turning a Raspberry Pi SBC into a bluetooth speaker - the configuration process is similar.

My full diffconfig, with drivers for the networking coprocessors

I am running “my own” build with what I can only describe as salvaged drivers for the networking coprocessors, following these directions. I’ve modified the provided diffconfig a fair amount for the other hardware, as well as some creature comforts like bash and nano, since I have more than enough space. The networking coprocessor kernel modules are a little bit unstable under certain conditions but greatly increase networking performance - I can get 450-500mbps using a wifi connection as the WAN with these, where otherwise it’ll tap out at a much lower speed. As I understand it, these will never be included in an official IPQ806x router build due to code licensing issues, but there are unofficial builds using these “NSS” kernel modules out there, namely those maintained by ACWifiDude - though I had to build this myself, since the OpenWRT support for this device is very fresh.

This includes some more general stuff like Adguard Home and a CalDAV server, as well as some USB serial drivers for interfacing with MCUs, for example in a 3d printer, but that is in its own section, for the most part. This should be enough for all peripherals of the Onhub to work, save the Zigbee chip. It’s an SPI chip and supposedly has some support in the kernel, but I’ve no idea if that’s something stubby or what. I haven’t specifically tried to put any sort of driver/module for this into my config yet, but SPI tools are built with these settings if you want to try to poke at it. I haven’t tried to get anything out of it as of yet.

diffconfig

# Use "make defconfig" to expand this to a full .config
CONFIG_TARGET_ipq806x=y
CONFIG_TARGET_ipq806x_chromium=y
CONFIG_TARGET_MULTI_PROFILE=y
CONFIG_TARGET_DEVICE_ipq806x_chromium_DEVICE_tplink_onhub=y
CONFIG_TARGET_DEVICE_PACKAGES_ipq806x_chromium_DEVICE_tplink_onhub=""
#CONFIG_TARGET_DEVICE_ipq806x_chromium_DEVICE_asus_onhub=y
#CONFIG_TARGET_DEVICE_PACKAGES_ipq806x_chromium_DEVICE_asus_onhub=""

# NSS Drivers - seemingly somewhat unstable under certain conditions. 
#Comment out if you aren't building with the NSS modules.
CONFIG_PACKAGE_kmod-qca-nss-drv=y
CONFIG_PACKAGE_kmod-qca-nss-ecm-standard=y
CONFIG_PACKAGE_kmod-qca-nss-gmac=y
CONFIG_PACKAGE_kmod-qca-nss-drv-qdisc=y
CONFIG_PACKAGE_kmod-nss-ifb=y
CONFIG_PACKAGE_kmod-qca-nss-drv-pppoe=y
CONFIG_PACKAGE_kmod-qca-nss-drv-pptp=y
# CONFIG_PACKAGE_kmod-qca-nss-drv-l2tpv2 is not set
# CONFIG_PACKAGE_kmod-qca-nss-drv-tunipip6 is not set
CONFIG_PACKAGE_kmod-qca-nss-crypto=y
CONFIG_PACKAGE_kmod-qca-nss-drv-igs=y

CONFIG_PACKAGE_ath10k-firmware-qca988x=y
CONFIG_PACKAGE_kmod-ath3k=y
# CONFIG_PACKAGE_ath10k-firmware-qca988x-ct is not set
CONFIG_PACKAGE_kmod-ath10k=y
# CONFIG_PACKAGE_kmod-ath10k-ct is not set

# Busybox tweaks
CONFIG_BUSYBOX_CUSTOM=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVE_ON_EXIT=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_FLAGS=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_REGEXP=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_WINCH=y

#general server-y shit
CONFIG_PACKAGE_adguardhome=y
CONFIG_PACKAGE_luci-app-radicale2=y

# Add-on programs
CONFIG_DROPBEAR_ECC=y
# CONFIG_PACKAGE_openvpn-openssl=y
CONFIG_PACKAGE_nano=y
CONFIG_PACKAGE_bash=y
CONFIG_PACKAGE_sudo=y
CONFIG_PACKAGE_htop=y
CONFIG_PACKAGE_cfdisk=y
CONFIG_PACKAGE_iperf3=y
CONFIG_PACKAGE_kmod-cryptodev=y
CONFIG_PACKAGE_libopenssl-devcrypto=y
CONFIG_PACKAGE_kmod-dnsresolver=y
CONFIG_PACKAGE_curl=y
CONFIG_PACKAGE_ds-lite=y
CONFIG_PACKAGE_openssh-sftp-server=y
CONFIG_PACKAGE_usbutils=y
CONFIG_PACKAGE_kmod-ramoops=y
CONFIG_PACKAGE_kmod-pstore=y
CONFIG_PACKAGE_pulseaudio-daemon-avahi=y
CONFIG_PACKAGE_pulseaudio-profiles=y
CONFIG_PACKAGE_pulseaudio-tools=y
CONFIG_PACKAGE_kmod-sound-core=y


# USB device mount & file systems support
CONFIG_PACKAGE_kmod-usb-serial-ch341=y
CONFIG_PACKAGE_kmod-bluetooth=y
CONFIG_PACKAGE_kmod-input-uinput=y
CONFIG_PACKAGE_alsa-utils=y
CONFIG_PACKAGE_mpg-123=y
CONFIG_PACKAGE_sbc=y
CONFIG_PACKAGE_bluez-daemon=y
CONFIG_PACKAGE_bluez-libs=y
CONFIG_PACKAGE_bluez-utils=y
CONFIG_PACKAGE_dbus=y
CONFIG_PACKAGE_block-mount=y
CONFIG_PACKAGE_cryptsetup=y
CONFIG_PACKAGE_dosfstools=y
CONFIG_PACKAGE_e2fsprogs=y
CONFIG_PACKAGE_f2fs-tools=y
CONFIG_PACKAGE_kmod-crypto-ecb=y
CONFIG_PACKAGE_kmod-crypto-xts=y
CONFIG_PACKAGE_kmod-crypto-iv=y
CONFIG_PACKAGE_kmod-crypto-misc=y
CONFIG_PACKAGE_kmod-crypto-user=y
CONFIG_PACKAGE_kmod-fs-ext4=y
CONFIG_PACKAGE_kmod-fs-f2fs=y
CONFIG_PACKAGE_kmod-fs-vfat=y
CONFIG_PACKAGE_kmod-nls-base=y
CONFIG_PACKAGE_kmod-nls-cp1250=y
CONFIG_PACKAGE_kmod-nls-cp437=y
CONFIG_PACKAGE_kmod-nls-cp850=y
CONFIG_PACKAGE_kmod-nls-iso8859-1=y
CONFIG_PACKAGE_kmod-nls-iso8859-15=y
CONFIG_PACKAGE_kmod-nls-utf8=y
CONFIG_PACKAGE_kmod-usb-storage=y
CONFIG_PACKAGE_libblkid=y
CONFIG_PACKAGE_ntfs-3g=y
CONFIG_PACKAGE_nfs-utils=y
CONFIG_PACKAGE_tc-tiny=y
# CONFIG_PACKAGE_wsdd2=y


# WLAN/WPS support
CONFIG_PACKAGE_hostapd-utils=y
CONFIG_WPA_MSG_MIN_PRIORITY=4
CONFIG_PACKAGE_wpad-openssl=y
# CONFIG_PACKAGE_wpad-basic-wolfssl is not set
# CONFIG_PACKAGE_libustream-wolfssl is not set

# SSL certificates
CONFIG_PACKAGE_ca-certificates=y

# Luci (SSL from OpenSSL)
CONFIG_PACKAGE_luci-ssl-openssl=y
# CONFIG_PACKAGE_luci-app-hd-idle=y
# CONFIG_PACKAGE_luci-app-minidlna=y
CONFIG_PACKAGE_luci-app-opkg=y
# CONFIG_PACKAGE_luci-app-samba4=y
CONFIG_PACKAGE_luci-app-sqm=y
# CONFIG_PACKAGE_luci-app-wifischedule=y
CONFIG_PACKAGE_luci-app-wol=y


# Luci statistics
CONFIG_PACKAGE_luci-app-statistics=y
CONFIG_PACKAGE_collectd-mod-conntrack=y
CONFIG_PACKAGE_collectd-mod-cpufreq=y
CONFIG_PACKAGE_collectd-mod-dhcpleases=y
CONFIG_PACKAGE_collectd-mod-entropy=y
CONFIG_PACKAGE_collectd-mod-exec=y
CONFIG_PACKAGE_collectd-mod-thermal=y
CONFIG_PACKAGE_collectd-mod-wireless=y

Other distros?

I would think that one of Cadmium or hexdump’s imagebuilder ‘velvet OS’, build systems that have support for ARM ChromeOS devices that use depthcharge as a bootloader, could be leveraged to run more conventional distributions of Linux on the Onhub and Google Wifi (they share this bootloader, and are both armv7) but I’ve not spent the time trying. Void Linux on these would be pretty nice though, and it has an armv7 rootfs tarball as part of its build system. Cadmium already supports Void. The lack of progress on this is a victim of my laziness, but it’s seemingly very possible, at least as far as I know. Watch this space?

Other fringe hacky stuff

Is there a TTL serial header? Maybe. There’s some sort of pin header hanging out on the PCB. Have not needed it as of yet, since recovery from a bricked OpenWRT install via depthcharge is pretty easy.

The SPI zigbee chip mainly needs work, all the other hardware is supported with little fuss, surprisingly. I kinda don’t know where to start with that, but like I said, it’s somewhere in the Linux kernel, with the support coming as an upstream contribution from OpenWRT, though I am not sure what exactly that support entails. The precise chip is a Silicon Labs EM3581 chip, and it uses a Skyworks SKY66109 chip in the signal transmission in some way. (LATER EDIT: I am not very hopeful about getting this chip to work, at least not myself. It’s a SoC in its own right with a custom instruction set, and it is connected over the more unusual SPI bus rather than the chip’s USB protocol. You also need to register a development kit to get access to a lot of the software development frameworks.)

The following is very speculative.. but I noticed that the LED ring is connected over I2C. I seem to remember that multiple I2C devices can be chained off of one I2C bus… so maybe there is a way to utilize I2C devices with this router?

And.. just a general question, to provoke some thought in anyone interested: how exactly does the Onhub stock firmware use the Krait networking coprocessors? I’m not entirely sure where the NSS drivers from qosimo / ACWifiDude’s build come from, maybe the ChromeOS firmware would have some that are better suited? I’m not sure I quite have the skills to answer this question myself, but you can download the recovery firmware (which should contain the whole OS in some form) here, and a backup I took of the Onhub’s stock firmware as it came to me in the mail here.

>> Home