ModemManager support for E3372 LTE sticks in modem mode, packaged for
Raspberry Pi OS: the ZOWEE (Brovi) E3372-325 and the Huawei
E3372h-320 and E3372h-153. Instead of running as a HiLink router with its own NAT at
192.168.8.1, the stick is switched to modem mode and handled by ModemManager
and NetworkManager. The host gets the carrier IP directly (ppp0 on the
E3372-325, wwan0 on the Huawei sticks), and ModemManager reports signal, cell
and operator information.
The package contains:
- usb_modeswitch configurations that switch the sticks to modem mode,
- a udev rule that binds the kernel's
optiondriver to the E3372-325's AT ports, - ModemManager's Huawei plugin with patches for the E3372-325, and its udev rules.
The E3372h-320 and E3372h-153 only need the usb_modeswitch configuration; the kernel and ModemManager already support them in modem mode.
| OS | Raspberry Pi OS (64-bit) trixie (Debian 13) |
| Architecture | arm64 only |
| ModemManager | modemmanager 1.24.0-1+deb13u1 from Debian trixie (also what Raspberry Pi OS trixie installs) |
The plugin uses ModemManager-internal symbols, so each release works with
exactly one modemmanager version, see
Compatibility and updates.
| USB ID (storage → modem mode) | Device | Status |
|---|---|---|
3566:2001 → 3566:2001 |
ZOWEE E3372-325, sold as Brovi or Huawei E3372-325 | Supported, data over PPP |
12d1:1f01 → 12d1:155e |
Huawei E3372h-320 | Supported, data over NCM (wwan0) |
12d1:1f01 → 12d1:155e |
Huawei E3372h-153 (HiLink firmware) | Supported, data over NCM (wwan0) |
The E3372-325 shares the name with Huawei's E3372 sticks but is a different design (Marvell chipset, Huawei-compatible firmware), see docs/E3372-325.md. The E3372h-320 and E3372h-153 are Huawei (HiSilicon) designs, see docs/E3372h-320.md and docs/E3372h-153.md.
Important
All Huawei sticks that start as 12d1:1f01 are switched to modem mode,
not only the E3372h-320 and E3372h-153. The package's
/etc/usb_modeswitch.d/12d1:1f01 overrides usb-modeswitch-data, which
switches them to HiLink mode. To keep another 12d1:1f01 stick in HiLink
mode, delete that file (it's a conffile, so upgrades won't bring it back).
Other Huawei HiLink sticks reported to start as 12d1:1f01 (not tested with
this package):
| Model | Modem mode after the HuaweiAlt message |
|---|---|
| E8372 (LTE, Wi-Fi) | 12d1:155e, reported |
| E353, E303, E3131, E3531 (3G) | No reports found |
Debian's Huawei plugin handles Huawei's vendor ID, so a stick that comes up in
modem mode most likely works with ModemManager. A stick that doesn't accept the
HuaweiAlt message may end up in neither mode; delete the file above to use it
in HiLink mode. The E3372s-153 with "stick" firmware starts as 12d1:1505 and
isn't affected.
Download the .deb for your release from the
releases page
and install it with apt:
sudo apt install ./modemmanager-e3372_<version>_arm64.debThe package reloads the udev rules and restarts ModemManager. Re-plug the stick (or reboot) so it's switched to modem mode.
Check that ModemManager handles the stick:
mmcli -L # e.g. [ZOWEE TECHNOLOGY (HEYUAN) CO., LTD.] E3372-325
mmcli -m any | grep plugin # plugin: huaweiThen create a NetworkManager connection with your SIM's APN. On the E3372-325, IPv6 must be disabled, the stick ends PPP sessions that negotiate IPv6:
sudo nmcli connection add type gsm ifname '*' con-name cellular apn <your-apn> ipv6.method disabledThe E3372h-320 also works with IPv6 enabled (IPv4v6 bearer). The E3372h-153 only supports IPv4.
NetworkManager connects automatically and brings up ppp0 (E3372-325) or
wwan0 (E3372h-320, E3372h-153). Signal values:
mmcli -m any --signal-setup=10
mmcli -m any --signal-getImportant
The package replaces ModemManager's Huawei plugin. It diverts Debian's
libmm-plugin-huawei.so and 77-mm-huawei-net-port-types.rules
(dpkg-divert, the originals are kept as *.distrib) and installs patched
builds of both. The patches add support for the E3372-325 and make
reconnecting more robust for Huawei NDIS modems; other behavior stays
unchanged (see Background).
Removing the package restores Debian's files.
The package can be installed in a chroot, e.g. with
pi-gen or
pimod. Without a running systemd, the
package scripts only set up the diversions. Example for a pimod Pifile:
MM_E3372_VERSION=1.24.0-2
RUN sh -c "curl -fsSL -o /tmp/modemmanager-e3372.deb https://github.com/trackIT-Systems/modemmanager-e3372/releases/download/${MM_E3372_VERSION}/modemmanager-e3372_${MM_E3372_VERSION}_arm64.deb"
RUN apt-get install -y /tmp/modemmanager-e3372.deb
RUN rm /tmp/modemmanager-e3372.debapt-get install fails the build if the image's modemmanager isn't the
version the release was built for.
The package depends on the exact modemmanager and libmm-glib0 version it
was built against, e.g. modemmanager (= 1.24.0-1+deb13u1). apt refuses to
install it next to any other ModemManager version, and the plugin can't end up
loaded into a ModemManager it doesn't fit.
When Debian publishes a new modemmanager for trixie:
apt upgradeholds the newmodemmanagerback.apt full-upgradewould remove this package to install it.
Wait for a release of this repository for the new version, or build one (see
Maintenance). Check the installed version with
apt-cache policy modemmanager.
All sticks start in storage (CD-ROM) mode after every power-on and are switched to modem mode each time by the package's usb_modeswitch configuration; nothing is stored in the sticks.
E3372-325:
- Port layout in modem mode: interface 1 AT and PPP (primary), interface 2 Marvell diagnostics (ignored), interface 4 AT (secondary), interfaces 5/6 NCM (ignored, it never gets a link).
- Throughput (LTE, roaming, single samples): about 6 Mbit/s down, 1 Mbit/s up, 80–90 ms ping. PPP framing costs no measurable CPU on a Pi 5.
E3372h-320:
- Port layout in modem mode (
12d1:155e): interface 0 AT/PPP, interface 1 diagnostics (not used), interface 2 AT (primary), interfaces 3/4 NCM (wwan0, used for data). The kernel bindsoptionandcdc_ncmby itself. - Data: ModemManager dials with
^NDISDUPand configureswwan0with the address the stick reports (static IPv4, no DHCP client needed).
E3372h-153: same USB IDs, ports and data connection as the E3372h-320,
except that all serial interfaces are ff/ff/ff and ModemManager takes the
port types from ^GETPORTMODE.
Back to HiLink: apt purge modemmanager-e3372 (a plain remove keeps the
usb_modeswitch configurations, which would keep switching the sticks to modem
mode), then re-plug. The E3372-325 has to be switched back by hand with
usb_modeswitch -v 3566 -p 2001 -J; for the Huawei sticks, usb-modeswitch-data
does that on its own.
Firmware details are in docs/E3372-325.md (USB modes, the attach context, supported AT commands, how to test a change), docs/E3372h-320.md and docs/E3372h-153.md.
Stock Raspberry Pi OS switches the E3372h-320 and E3372h-153 to HiLink mode: the
12d1:1f01 entry in usb-modeswitch-data sends the HuaweiNew message. With the
HuaweiAlt message instead, the sticks come up in modem mode, which the kernel
(option, cdc_ncm) and ModemManager's Huawei plugin already support.
Stock Raspberry Pi OS can't run the E3372-325 in modem mode:
- usb-modeswitch-data, the kernel's
optiondriver and ModemManager don't know3566:2001. - ModemManager's Huawei plugin only accepts Huawei's vendor ID, so the stick
ends up with the generic plugin: no signal values (
+CESQisn't supported), and with no port hints it may pick the wrong AT port. - After every boot, the stick's firmware defines its own LTE attach context (cid 7). ModemManager reuses it because the APN matches, but PPP on that context never gets through IPCP; NetworkManager retries and gives up. Any context the host defines works.
patches/ applies to ModemManager 1.24.0 and only touches the Huawei plugin:
| Patch | Change |
|---|---|
| 0001 | Accept 3566:2001 in the Huawei plugin; udev rules for its port types, skip ^GETPORTMODE (unsupported), ignore the NCM port |
| 0002 | New udev tag ID_MM_HUAWEI_ATTACH_PROFILE_ID: hide the firmware's attach context from the profile list, so ModemManager defines and dials its own; raise the minimum profile id to 1 (the stick rejects cid 0) |
| 0003 | Don't clear the extended signal values before querying ^HCSQ?: the stick answers with a bare OK and only reports ^HCSQ unsolicited |
| 0004 | Before dialing with ^NDISDUP, check ^NDISSTATQRY? and disconnect a connection that is still active in the modem (e.g. after ModemManager was killed while connected). Without it, every dial attempt fails with ERROR until the modem is power cycled |
0001 and 0002 only change behavior for devices tagged by the udev rules (the
E3372-325). 0003 changes when Huawei devices drop old ^HCSQ values: on the
next ^HCSQ message instead of before every query. 0004 adds one
^NDISSTATQRY? query to every NDIS connection attempt of Huawei modems (the
E3372h-320 and E3372h-153, not the E3372-325, which uses PPP) and only acts if a connection
is already active.
The E3372h-320 and E3372h-153 don't need 0001–0003: they work with Debian's plugin as well (tested), but only patch 0004 lets them recover from a leftover connection.
The patches are meant to go upstream to ModemManager. Once a ModemManager with
them is shipped by Debian, the plugin part of this package is obsolete; the
usb_modeswitch and option parts belong in usb-modeswitch-data and the kernel.
Debian's 1.24.0-1+deb13u1 only patches the Fibocom plugin, so upstream
1.24.0 is ABI-identical to it.
Tested on a Raspberry Pi 5 with modemmanager 1.24.0-1+deb13u1,
NetworkManager 1.52.1, kernel 6.18 (Raspberry Pi), SIM roaming on LTE.
ZOWEE E3372-325 (firmware 3.0.2.61(H057SP5C983)):
- Cold start with the package installed: the stick boots in storage mode,
usb_modeswitch switches it,
optionbinds the AT ports, the Huawei plugin takes the modem with the right ports, and NetworkManager connects on its own.ppp0was up 38 s after a host reboot and about 45 s after a firmware reboot of the stick (AT^RESET). - With data checked after each step: 3 of 3 NetworkManager disconnect/reconnect
cycles (about 2 s each), a ModemManager restart (data after about 30 s),
mmcli --disable/--enable, and a re-attach that wiped the stick's contexts. - Signal quality, access technology, operator and extended LTE signal values (RSSI, RSRP, RSRQ, SNR) are reported.
Huawei E3372h-320 (firmware 10.0.3.1(H192SP1C983), hardware
CL4E3372HM):
- Cold start with the package installed: the stick boots as
12d1:1f01, usb_modeswitch switches it to12d1:155e, the Huawei plugin takes it (^NDISDUPonwwan0) and NetworkManager connects on its own. The modem was created 41 s after a host reboot (data right after), and data flowed 63 s after a firmware reboot of the stick (AT^RESET). - With data checked after each step: 3 of 3 NetworkManager disconnect/reconnect cycles (2–4 s each) and a ModemManager restart (data after about 40 s).
- IPv4 and IPv4v6 bearers work; signal quality and extended LTE signal values are reported.
- Physical replug: 5 of 5, including a different USB port (on the other USB controller); data about 42 s after plugging in each time.
- ModemManager killed with SIGKILL while connected: 3 of 3 recovered, data about 40 s after the restart (patch 0004; without it, never).
Huawei E3372h-153 (HiLink firmware 22.329.63.00.21, hardware
CL2E3372HM):
- Cold start with the package installed: switched to
12d1:155e, the Huawei plugin takes it (^NDISDUPonwwan0) and NetworkManager connects on its own. Data 46 s after a host reboot (kernel start) and about 50 s after a firmware reboot of the stick (AT^RESET). - With data checked after each step: 3 of 3 NetworkManager disconnect/reconnect cycles (about 1 s each), a ModemManager restart (data after 36 s) and an inhibit/uninhibit (data after 29 s).
- ModemManager killed with SIGKILL while connected: 3 of 3 recovered, data 36–38 s after the restart (patch 0004).
- IPv4 bearer; signal quality and extended LTE signal values are reported. About 3 Mbit/s down and up (LTE, roaming, single sample).
- Physical replug: 5 of 5, alternating between both USB controllers (
1-2,3-2); modem mode 1.3 s and data 38–40 s after plugging in each time.
Known issues:
- The attach context's cid (7) is hard-coded in the udev rules; only tested with one carrier.
- Once,
mmcli --disabletimed out while connected; it didn't happen again.
On Raspberry Pi OS or Debian trixie, arm64 (or in a debian:trixie container):
apt-get install --no-install-recommends \
build-essential ca-certificates dpkg-dev git gettext \
meson ninja-build pkg-config patchelf python3 xsltproc \
libdbus-1-dev libglib2.0-dev libgudev-1.0-dev \
libmbim-glib-dev libqmi-glib-dev libqrtr-glib-dev \
libpolkit-gobject-1-dev libsystemd-dev systemd-dev modemmanager
./build.sh
./check-symbols.shbuild.sh fetches the ModemManager release pinned in versions.env, applies
patches/, builds only the Huawei plugin and packages
dist/modemmanager-e3372_<version>_arm64.deb with:
etc/usb_modeswitch.d/12d1:1f01
etc/usb_modeswitch.d/3566:2001
usr/lib/aarch64-linux-gnu/ModemManager/libmm-plugin-huawei.so (diverts Debian's)
usr/lib/udev/rules.d/40-e3372-usb_modeswitch.rules
usr/lib/udev/rules.d/70-e3372-option.rules
usr/lib/udev/rules.d/77-mm-huawei-net-port-types.rules (diverts Debian's)
usr/share/doc/modemmanager-e3372/{README.md,E3372*.md,copyright,changelog.Debian.gz}
It refuses to run if build/ exists; remove it for a fresh build.
check-symbols.sh verifies that every ModemManager symbol the plugin imports is
exported by the installed modemmanager/libmm-glib0, and that the module
exports what ModemManager's loader requires. CI runs it on every build,
test-installs the package on Debian trixie with the Raspberry Pi OS archive
(archive.raspberrypi.com) enabled, i.e. the package set of Raspberry Pi OS
trixie, and checks that installing and removing it sets up and removes the
diversions.
- Update
MM_TAG,MM_COMMITandMM_DEBIAN_VERSIONinversions.env. Checkdebian/patchesof the new Debian version for changes to the Huawei plugin or outsidesrc/plugins/: the package replaces Debian's Huawei plugin, so a Debian fix there would otherwise be lost. - Rebase
patches/if needed (git amonto the new tag, thengit format-patch -N --zero-commit --no-signature <tag>..HEAD). - Build, test on hardware, and release (see below).
Releases are tagged <ModemManager version>-<revision>, like Debian package
revisions. The tag is also the package version:
1.24.0-1 first release for ModemManager 1.24.0
1.24.0-2 our own changes (fixes, new devices, ...) or a Debian-only update
of ModemManager 1.24.0 (e.g. +deb13u2), still for 1.24.0
1.26.0-1 rebuilt for ModemManager 1.26.0, revision starts again at 1
The exact Debian ModemManager version is in versions.env and in the package's
Depends. Tags have no v prefix.