There is something satisfying about a binary blob collapsing into a short shell script. That is what happened when a developer traced through Lenovo’s WWAN unlock tool and found it was essentially a complicated wrapper around a handful of AT commands that any shell script could send directly. The underlying protocol is 45 years old. The modem speaks it fluently. The blob was just obscuring that fact.
What WWAN Unlock Actually Means
Modern ThinkPads ship with M.2 WWAN cards, typically from Fibocom, Quectel, or Sierra Wireless. These are cellular modems: full radio subsystems that connect to LTE or 5G networks. The hardware is capable, but reaching that capability on Linux has historically required jumping through hoops that Windows users never see.
The “unlock” step is not about breaking carrier locks in the colloquial sense. It is closer to an initialization gate: Lenovo’s firmware or a userspace tool performs a handshake with the modem before the radio stack becomes usable. In some configurations this relates to FCC unlock requirements, which mandate that devices sold in the US support being unlocked from carrier restrictions. In others it is a capability-enable sequence that sets specific modem operating parameters. Either way, the modem is sitting there, fully functional, waiting for a correct command sequence before it will cooperate.
Lenovo ships a binary executable to perform this sequence on Linux. It runs, the modem unlocks, ModemManager picks it up, and everything works. The problem is that the binary is opaque: architecture-tied, impossible to audit, liable to break across kernel versions, and entirely unnecessary given that the protocol underneath it is well documented.
AT Commands: A Protocol That Refuses to Die
The Hayes command set was designed for the Smartmodem in 1981. Dennis Hayes and Dale Heatherington built a simple ASCII protocol where commands begin with AT (attention) and the modem responds with OK, ERROR, or result data. It was meant for 300-baud dial-up modems and has since been extended, extended again, and extended once more to cover every generation of cellular networking.
The 3GPP specifications added the + prefix extensions: AT+CGMM for model identification, AT+CPIN for SIM PIN management, AT+COPS for network operator selection. Qualcomm added its own proprietary extensions. So did Sierra Wireless, Fibocom, and Quectel. The result is a protocol with a documented core and vendor-specific extensions, most of which are described in public datasheets if you know where to look.
Accessing this from Linux is straightforward. The modem exposes several USB serial interfaces. On a typical Quectel EM120R you get /dev/ttyUSB0 through /dev/ttyUSB3, with one of those designated as the AT command port. You can write to it directly:
exec 3<>/dev/ttyUSB2
echo -e 'ATI\r' >&3
cat <&3 &
Or you can use socat for something cleaner:
socat - /dev/ttyUSB2,crnl
ModemManager normally claims the device and provides a higher-level D-Bus interface accessible via mmcli. But for initialization sequences that need to run before ModemManager takes over, or that ModemManager does not expose directly, direct serial access works fine.
What the Blob Was Actually Doing
The approach the hofstede.it post takes is the standard one for this kind of work: run the blob under strace, capture the file descriptor writes, decode the byte sequences. What you find is the blob opening a serial device and writing a sequence of AT commands: vendor-specific queries, status checks, a capability-enable string, acknowledgment reads. The exact commands vary by modem model, but the pattern is the same.
Once you have the command sequence, reproducing it in Bash is mechanical:
#!/usr/bin/env bash
set -euo pipefail
MODEM_PORT="/dev/ttyUSB2"
send_at() {
local cmd="$1"
printf '%s\r\n' "$cmd" > "$MODEM_PORT"
sleep 0.1
read -t 2 -r response < "$MODEM_PORT" || true
echo "$response"
}
# Identify the modem
send_at 'ATI'
# Vendor-specific unlock sequence
send_at 'AT+XGENDATA'
send_at 'AT+UNLOCK=...'
The actual commands in the published script are specific to the hardware in question. The point is that they are readable, modifiable, and require no trust in an opaque binary.
The Binary Blob Problem in Linux Hardware Support
Blobs in the Linux ecosystem come in a few forms. Kernel firmware blobs, distributed through linux-firmware, are the most visible: GPU microcode, WiFi firmware images, the contents of /lib/firmware. These are often genuinely non-replaceable, encoding DSP programs or radio calibration data that only the hardware vendor possesses. The Linux kernel ships without them and defers to the distro.
Then there are userspace blobs: executables or libraries that a vendor ships to perform some initialization or configuration task. These are different in character. They typically speak a protocol that the vendor did not invent, to hardware that is reasonably well documented, over an interface (serial, USB control transfers, MBIM, QMI) that has open implementations. The blob is not doing anything novel; it is just doing it opaquely.
Lenovo’s WWAN unlock tool falls squarely in this second category. The AT command protocol is documented. The modem’s extended AT command set is in the vendor’s datasheet. The serial interface is a standard USB CDC-ACM device. There is no technical reason this requires a binary, only an organizational one: it is easier for Lenovo to ship a compiled tool than to maintain and publish the command sequence.
The cost of that choice falls on the Linux ecosystem. The blob ties to a specific architecture (x86-64, usually), may carry glibc version dependencies, and cannot be cross-compiled for an ARM ThinkPad or a custom embedded build. When something goes wrong, there is no way to instrument it beyond strace. When it breaks on a new kernel, you wait for Lenovo to ship an update rather than patching it yourself.
ModemManager and the Broader Infrastructure
It is worth noting that the Linux modem stack has come a long way. ModemManager handles device detection, plugin-based initialization, and D-Bus interfaces for network managers. The mmcli tool exposes most of what you need for day-to-day modem management:
# List modems
mmcli -L
# Check modem status
mmcli -m 0
# Check SIM details
mmcli -m 0 --sim-status
# Enable modem
mmcli -m 0 -e
For QMI-based modems (which includes most Qualcomm-chipset devices like the Sierra Wireless EM7455), libqmi and the qmicli tool provide access to the lower-level QMI protocol that modern modems prefer over raw AT for data connections. MBIM is the alternative, implemented in libmbim. Both have active upstream development and reasonable documentation.
The gap that the unlock blob fills is pre-ModemManager initialization: something the kernel or modem requires before the device presents itself in a usable state. This is where vendor tooling tends to creep in, because it sits outside the normal device lifecycle that ModemManager manages. A udev rule can trigger a script at device insertion, which is exactly how the replacement Bash script can be integrated.
Why This Matters Beyond One Script
The immediate benefit is practical: the author has a WWAN module that works on Linux without a vendor binary. That is useful on its own. But the broader benefit is the documented command sequence itself. Anyone with the same hardware can now reproduce the unlock without tracking down the blob. The knowledge is transferable in a way that a binary is not.
This is how Linux hardware support improves incrementally. Someone reverse engineers a protocol, writes it down or publishes a script, and the next person does not have to repeat the work. The Linuxonmobile project, the postmarketOS contributors, the ThinkPad fan community on forums and wikis, all operate on this model. Kernel driver development is the same: someone traces what the Windows driver does and writes a free implementation.
For WWAN specifically, the ecosystem has improved substantially over the last five years. Fibocom modems that required patches and workarounds in 2020 are now supported natively in mainline ModemManager. Quectel’s Linux SDK, while proprietary, is at least documented. The trend is toward openness, even if the pace is uneven.
A 100-line Bash script replacing an opaque binary is a small thing in isolation. As a pattern, it is how vendor lock-in gets eroded over time: one traced system call at a time, one published AT command sequence at a time, until the blob is no longer necessary and nobody misses it.