Electronics, Firmware, hardware, Networking, Reverse engineering, Software

Initial analysis of the Starlink router gen2

It was fun to do reverse engineering of the original Starlink router. The article was also well received.
Sure, it would be great to do the same thing with the new Starlink router gen2. It’s not easy to get new hardware, but why should this stop the fun?

 

Do I have the new Starlink router?

Unfortunately, I don’t have the new router yet. But I have a photo of the router!

Big thanks to Phil from the Ingineerix channel! He was kind enough to disassemble his Starlink router and take many photos for me of the router’s internals.

Also, many thanks to SpaceX for releasing the GPL part of the router firmware. Let’s see what we can get from photos and the code repository.

Router overview

The new design combines router hardware and power supply with a proprietary Dishy connector.
There is no built-in Ethernet port, which is not the best solution. Users should use an external Ethernet adapter. I made a detailed review and analysis of this adapter.
The router’s front panel is made of glass and glued to a housing. It seems that the router is intended to be outdoor-ish. The Dishy and Power connectors on the bottom are also moisture-proof. It’s IP54 rated.
Also, there is a drawing of the orbital transfer ellipse from Earth to Mars on the front. Nice art šŸ™‚
Reported that it’s tough to remove the front glass panel.

Power supply

Under the front panel, we can find the mainboard, power supply, and heatsink plate.
Here is router internals with the mainboard removed.

The power supply is made by Chicony and produces 50V 2.4A for the Dishy and 12V 1.25A for the router itself.
The massive metal plate cools the router CPU and radio.

Mainboard

All router components are placed on a single side of the PCB.
The PCB has an odd shape to fit inside the housing with the power supply. I’m not sure that this positively affects production costs and the amount of waste.

But, the number of components was significantly reduced compared to the first-gen router. The total BOM cost is definitely lower.

MT7629 SoC

The heart of the new system is MediaTek MT7629 SoC.
It’s hard to find detailed information about this chip, but we can get some information from the sources repository and Google.
MT7629 it’s a dual-core ARM Cortex-A7 + MT7615-compatible 3-chain radio. Plus built-in 1G Ethernet PHY and two SGMII interfaces for external PHYs/switch.
Simplified diagram of the SoC:
Where did I get information about the mt7615 radio? The source code repository contains a lot of information.
WiFi up/down script: openwrt/package/mtk/drivers/wifi-profile/files/mt7615e.lua
Radio calibration data: openwrt/package/mtk/drivers/wifi-profile/files/mt7629
Plus, build configuration:
3938 CONFIG_first_card_name="MT7629"
3939 CONFIG_first_card_profile_path="/etc/wireless/mediatek/mt7629.1.b0.2g.dat;/etc/wireless/mediatek/mt7629.1.b1.5g.dat"
3940 CONFIG_first_card_init_script="/lib/wifi/mt7615e.lua;/lib/wifi/mt7615e.lua"
3941 CONFIG_first_card_init_compatible="mt7615e;mt7615e"
Initially, I thought there were two external radio ICs under the RF shields. But this would be too expensive a solution, and there is no room for PCIe radio ICs.
Plus, MediaTek declares this SoC as an inexpensive all-in-one solution for WiFi routers.

RF front end

Let’s look at the antenna design and RF front end.
It’s unknown what exactly is under those RF shields. But since the SoC contains a fully integrated WLAN, there are nothing more than Power Amplifiers, Low Noise Amplifiers, Filters, and Switches inside cans.

 

Ch0 and Ch2 antennas design was derived from the original router.
But this is a 3×3 (3 TX, 3 RX) MIMO radio. That’s why we have a third CH1 antenna here. It’s a simple patch antenna.
The new antenna layout helps to create spatial diversity for the optimal MIMO operation. This is definitely better than it was in the original router.

Marked square elements are RF diplexers, like this one. These elements allow the connection of the 2.4 GHz and 5 GHz lines to the single antenna.
It’s a typical layout of the dual-band WiFi router.
Three identical channels:
Interestingly, CH1 2.4 GHz components are located under the first shield, and 5 GHz is under the second.

WiFi characteristics of the system:

2.4 GHz 802.11n 3×3 MIMO
Channel bandwidth, MHz: 20, 40

5 GHz 802.11ac 3×3 MU-MIMO
Channel bandwidth, MHz: 20, 40, 80

Max clients (802.11n + 802.11ac): 255
Please note that this is just a MAC table size of the chip. This means that this Access Point can hold up to 255 connected clients simultaneously. But this doesn’t mean that all 255 clients will work effectively. Of course, they don’t.

 

Tx power and sensitivity

The SoC built-in integrated PA can output up to 23.5 dBm at 5GHz.
RX sensitivity is around -94 dB.

It’s unknown what’s under those RF cans, so we don’t know the real characteristics of the RF front. I expect higher output power around 25-27 dBm and a similar (or less) RX sensitivity around -94 -90 dB.

In general, it’s a good and modern WiFi access point.

Ethernet

There are two Ethernet lines. The first one is WAN, and it’s used for the Dishy connection. WAN interface uses SoC built-in Ethernet PHY. Only external components are powerful PoE magnetics and capacitors.
Additional external PHY 88E1512 supports the LAN interface. This is the Alaska-series PHY from Marvell. There is no Ethernet magnetics on the board.
This PHY drives the transformer inside the external Ethernet adapter.

The device is connected to one of the SGMII lines of the SoC.

Dishy PoE controller

There is a good question on Starlink GitHub.
Let’s figure this out! šŸ™‚

Here is a close-up mosaic photo of this area:

What we can see here it’s a MOSFET for switching Dishy power on and off. Little QFN IC should be the PoE controller.
50V and 2A power supply means that Starlink uses 4-pair 802.3bt PoE. This is the latest PoE standard. I’m not sure that SpaceX 100% follows the standard here.

Unfortunately, I couldn’t find any information about the PoE PSE controller. I suspect that it might be something from the LTC lineup. It might be even LTPoE++. Not sure.

On the right, there is an operational amplifier and many transistors.
A big 0.05 Ohm SMD resistor, it’s a definitely current shunt. This means that the operational amplifier it’s a current measurement circuit.
Basically, the operational amplifier measures voltage difference across the shunt terminals. Due to high impedance, there is no current flow to the operational amplifier input. It’s all about only the voltage difference.

Typically, the current shunt is connected to the PoE controller directly. But, in this case, they decided to use an external amplifier for some reason. It might be the requirements of the PoE controller IC.
Or, all of this might be an effect of the chip shortage šŸ™‚

Interesting to note that the Vss pin of the operational amplifier is not connected to the ground directly. An additional circuit that “lifts” the ground for about 0.5 V allows the amplifier to measure lower values, down to 0 V.

Please excuse the crudity of these schematics. I didn’t have time to build it to scale or paint it.

I tried to recreate the schematic of this area.
Sure, there are a lot of unknowns. I don’t have the board, so I can’t trace all the lines. Also, I couldn’t identify some components. Plus, there might be incorrectly identified components.
Click on the image for the full resolution.

I marked unknown lines and questionable components with the “?” symbol.
Q1 MOSFET switches 50V supply for the Dishy. There is a driver circuit on two transistors. It’s always important to drive power MOSFET properly.
“Dishy PWR ON” should be connected to the PoE controller, so the 50V is applied only when the controller detects the connected PD controller on the other side (Dishy).
The operational amplifier channel 1 measures Dishy current on 0.05 Ohm shunt.
I don’t know what the second opamp channel is doing. Its non-inverting input is connected somewhere.

Both channels’ outputs are connected to the transistors. This circuit looks like an emitter follower. I couldn’t identify two components marked as “ST”. It might be some MOSFET, so the emitter follower regulates the current flowing through those MOSFETs.
Finally, this circuit should be connected to the PoE controller. It’s hardware protection against short circuits and other problems with Dishy.
Sure, some lines may be connected to the SoC to monitor the voltage/current from the software.

STSAFE

There is one more question in the Starlink repository:

What the device at I2C address 0x20 does.

We know from the previous article that this device is a STSAFE-A110 security/auth chip.Ā  This chip is doing the same job in the new router, plus now it’s a part of the boot process.

The STSAFE, besides providing the cert and signing capabilities that
authenticates our device as a genuine SpaceX device, also has extra zones. 
We have repurposed zone 6 to store a 32bit boot counter. This counter is used to
determine whether to boot set 0 or 1 of our FIPs and Kernels. This builds in
redundancy in the event one set is inoperable. The parity of the counter is
used to determine the side. The boot counter is also communicated to the next
boot loader (U-boot) by storing it in the TRANSFER_LEN register of the i2c
MMIO (this store now happens right after select_boot_partition() returns).
This was the easiest way to pass the parameter with minor modifications to
how ATF crawls the bootloader chain.

Zones 7 and 8 of the STSAFE contain built-in decrementing counters. These
counters are used for anti-rollback functionality (the rest of the system
treats the anti-rollback counter as incrementing, so the revoked version is
"flipped" by subtracting itself from 500,000, the initial value of the
STSAFE's decrementing counters).

Router block diagram

There might be some inaccuracies, but overall it looks like this.

Firmware

The new firmware is based on LEDE (OpenWrt) 17.01 and MediaTek SDK. SpaceX team claimed that they are trying to remain as close as possible to upstream OpenWrt.

GitHub repository contains almost everything except for proprietary MediaTek drivers and some tools. Also, some of the SpaceX code remains closed, but binaries are there.

Also, this time we have Docker and some additional scripts. Thanks šŸ™‚
But this doesn’t help to build the repository. Some OpenWrt files are missing. Plus, there is a problem with the bootloader signature.
Starlink router uses secure boot, so a certificate is required to build with bootloader binaries. Of course, there is no SpaceX certificate in the repository. But the build system expects this file. This breaks the build process.
I decided to introduce an additional flag, BUILD_BOOTLOADERS, to solve this issue. This flag disables the compilation of the bootloaders.
Both issues are solved in my commits here and there.

System boots from the single NAND chip. The first stage bootloader is burned inside the SoC ROM.
The NAND contains a second-stage bootloader, u-boot, two copies of the Linux kernel, and two operating system copies. Plus a few additional partitions.

Flash layout:

Partition nameStart offsetLength
BL20x000000x0080000
InactiveFIP0x800000x0200000
ActiveFIP0x2800000x0200000
Config0x4800000x0080000
Factory0x5000000x0200000
InactiveKernel0x20000000x2000000
ActiveKernel0x40000000x2000000
Storage0x60000000x1800000

BL2 it’s the second-stage bootloader that starts with the SoC ROM.
This bootloader performs initialization of the hardware: CPU, Memory, and security.
The next stage is u-boot in the FIP container. BL2 selects one of the FIP instances from InactiveFIP or ActiveFIP. The logic is described above in the STSAFE chapter. At this stage, BL2 verifies the signature of the FIP image. Invalid or unsigned FIP images are not booted.

U-boot performs vendor-specific initialization and routines like recovery and booting of the operating system.

Partitions InactiveKernel and ActiveKernel contain squashfs images of the OpenWrt operating system. One is booting, and the second is a backup of the previous version. Perhaps these partition names were derived from the MediaTek SDK.

The Storage partition contains a UBI image with two UBIFS partitions.

Partition nameFilesystemSize
configUBIFS2 MiB
logUBIFS2 MiB

Here is the UBI configuration file. Both partitions are mounted at runtime as rw.

The system starts as a regular OpenWrt system.
SpaceX-specific tasks are defined at the end of etc/init.d/boot
First, a reverse filter is disabled:

# OpenWrt defaults leaves reverse path filters disabled by default, which
# allows LAN clients to spoof WAN addresses and vice versa. Enable on all
# interfaces for security and sanity.
for interface in /proc/sys/net/ipv4/conf/*/rp_filter; do
    echo 1 > ${interface}
done

The next step applies tons of firewall filters.

In the last stage, configures the Marvell Ethernet PHY.

Also, we have a new cool login banner:

And even a special version for Ukraine. Thanks, SpaceX, for the support!

wifi_control

As in the previous router, all the router operation is controlled by the proprietary wifi_control daemon written in the Go language.

Driver WiFi configuration is stored in plain text format. The file format is typical for the MediaTek platform.
I’m not sure that wifi_control binary configuration is used this time, but probably yes.

Is it possible to run the new wifi_control on the Raspberry PI with the “old” STSAFE chip? Sure!

wifi_control properly detects the first-gen platform and tries to configure the IPQ401x system.
(Look at the Reboot reason šŸ™‚ )

Interestingly, the whole router operation is controlled by a single file /tmp/enable_bypass_mode
When this file is present, the router switches to the bypass mode: wifi_control is not running at all, and firewall rules are cleared except for outbound traffic.

Also, the wifi_control daemon runs a built-in web server. This webserver is implemented on the “HTML template” standard Go library.

Here are all the HTML templates files. JS code and CSS are in the neighborhood directory.

All these files are placed into the OpenWrt squashfs path /etc/www/templates/. We can find a lot of interesting there.
For example, the router configuration page. It looks like a factory/maintenance mode page that is not available for regular users:

You can see Go templates instead of real data.

But the most interesting it’s a mesh topology page.
It looks like SpaceX is implementing WiFi mesh technology. This means that they gonna separately sell routers or their variants.
I guess it’s not a big secret anymore, plus everything is in the open repository. That’s why I’m writing about this.

It looks like the whole page is just a Work In Progress. Sure, this page displays nothing if opened in the browser.
We need to provide data to see something.
I analyzed the JS code and found that the page expects JSON in a specific format to display IEEE 1905 topology.

The primary data source is topoJSON object in topology-merger.js

Let’s add some random data:

const topoJSON = [ 
{ 
"topology information": 
    [ 
        { 
            'Device role': 1,
            'AL MAC': "58:d5:6e:3e:05:f7",
            'Distance from controller': 0,
            'Upstream 1905 device': "58:d5:6e:3e:05:f7",
            'Radio Info': 
                    [
                        {
                            'channel': 142,
                            'BSSINFO':
                                [
                                    {
                                    'SSID': "Starlink Mesh Client 1",
                                    'connected sta info': [{ 'STA MAC address': "58:d5:6e:3e:05:f7" }]

                                    }
                                ]
                        },
                        {
                            'channel': 147,
                            'BSSINFO':
                                [
                                    {
                                    'SSID': "Starlink Mesh Client 2",
                                    'connected sta info': [{ 'STA MAC address': "58:d5:6e:3e:05:de"}]
                                    }
                                ]
                        }
                    ],
            'Other Clients Info': [ { 'Client Address': "dc:a6:32:02:76:76", 'Medium': "Ethernet" } ],
            'BH Info': []
        },
        { 
            'Device role': 2,
            'AL MAC': "32:f5:ee:3e:05:f8",
            'Distance from controller': 4,
            'Upstream 1905 device': "58:d5:6e:3e:05:f7",
            'Radio Info': 
                    [
                        {
                            'channel': 16,
                            'BSSINFO': []
                        }
                    ],
            'Other Clients Info': [],
            'BH Info': []
        }
    ]
} 
];

And the result:

This is a fun page to play. All objects are floating, and it’s possible to drag everything.

Well, I guess that’s all. I hope to write more when I will get the new router.
In the next articles, I will try to answer more questions from the SpaceX repository šŸ˜‰

Thanks for reading!

3 thoughts on “Initial analysis of the Starlink router gen2

  1. The PCB has an odd shape to fit inside the housing with the power supply. Iā€™m not sure that this positively affects production costs and the amount of waste.

    If you duplicate and rotate the board 180 degrees, it fits like a puzzle inside the other, thus saving quite a bit of PCB, and hence cost.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.