This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

ModemManager

The ModemManager project

ModemManager logo

This section provides information about the ModemManager daemon, the libmm-glib library, and the mmcli command line tool.

1 - Dependencies

Build and runtime dependencies of the ModemManager daemon.

Common dependencies

Before you can compile the ModemManager project, you will need at least the following tools:

  • A compliant C toolchain: e.g. glibc or musl libc, gcc or clang/llvm.
  • pkg-config, a tool for tracking the compilation flags needed for libraries.
  • The glib2 library.
    • For ModemManager >= 1.18, glib2 >= 2.56.
    • For ModemManager >= 1.14, glib2 >= 2.48
    • For ModemManager >= 1.6 and < 1.14, glib2 >= 2.36
    • For ModemManager >= 1.0 and < 1.6, glib2 >= 2.32
  • The libgudev library.
    • For ModemManager >= 1.18, libgudev >= 232.
    • For ModemManager >= 1.0 and < 1.18, libgudev >= 147.
  • The gettext tools.
    • For ModemManager >= 1.8, gettext >= 0.19.8.
    • For ModemManager >= 1.6 and < 1.8, gettext >= 0.19.3.
    • For ModemManager >= 1.0 and < 1.6, gettext >= 0.17.

In addition to the previous mandatory requirements, the project also has several optional dependencies that would be needed when enabling additional project features:

  • libmbim, in order to use the MBIM protocol.
    • For ModemManager >= 1.18, libmbim >= 1.26.
    • For ModemManager >= 1.14, libmbim >= 1.24.
    • For ModemManager >= 1.8 and < 1.14, libmbim >= 1.18.
    • For ModemManager >= 1.6 and < 1.8, libmbim >= 1.14.
    • For ModemManager >= 1.0 and < 1.6, libmbim >= 1.4.
  • libqmi, in order to use the QMI protocol.
    • For ModemManager >= 1.18, libqmi >= 1.30.
    • For ModemManager >= 1.16, libqmi >= 1.28.
    • For ModemManager >= 1.14 and < 1.16, libqmi >= 1.26.
    • For ModemManager >= 1.12 and < 1.14, libqmi >= 1.24.
    • For ModemManager >= 1.10 and < 1.12, libqmi >= 1.22.
    • For ModemManager >= 1.8 and < 1.10, libqmi >= 1.20.
    • For ModemManager >= 1.6 and < 1.8, libqmi >= 1.16.
    • For ModemManager >= 1.2 and < 1.6, libqmi >= 1.6.
    • For ModemManager >= 1.0 and < 1.2, libqmi >= 1.4.
  • libqrtr-glib, in order to use Qualcomm SoCs with the QRTR bus.
    • For ModemManager >= 1.18, libqrtr-glib >= 1.0.
  • libpolkit-gobject >= 0.97, in order to allow access control on the DBus methods.
  • systemd support libraries (libsystemd >= 209 or libsystemd-login >= 183), for the optional suspend and resume support.
  • gtk-doc tools, in order to regenerate the documentation.
  • gobject-introspection, in order to generate the introspection support.

Dependencies when building ModemManager 1.18 or later with meson

When building with meson, the following additional dependencies are required:

The following optional dependencies are available when building with meson:

  • bash-completion, in order to add completion support for the command line tools.

Dependencies when building ModemManager 1.18 or earlier with GNU autotools

When building with the GNU autotools, the following additional dependencies are required:

There are two main ways to build the library using GNU autotools: from a git repository checkout and from a source release tarball. When building from a git checkout instead of from a source tarball, the following additional dependencies are required:

2 - Building

How to build and install ModemManager.

This section provides information about how to build and install the ModemManager daemon and its libraries and utilities.

2.1 - Building ModemManager 1.18 or later with Meson

How to build and install the ModemManager daemon and libraries using the meson and ninja build systems.

The first stable series with support for building with the meson suite is 1.18. All the older stable series before 1.18 exclusively used the GNU autotools build system.

Building from a git checkout

When using meson, the builds are always triggered from git checkouts, there is no source release tarball involved. The basic build steps would be as follows:

  $ git clone https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git
  $ cd libqmi
  $ meson setup build --prefix=/usr --sysconfdir=/etc
  $ ninja -C build

Optional switches

Additional optional switches that may be given to the meson command above would be:

  • In Debian/Ubuntu systems the default location for libraries depends on the architecture of the build, so instead of the default /usr/lib path that would be in effect due to --prefix=/usr, the user should also give an explicit --libdir path pointing to the correct location. E.g. on a 64bit Ubuntu/Debian build, the user would use --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu.
  • If the MBIM protocol support is required, the additional -Dmbim=true should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • If the QMI protocol support is required, the additional -Dqmi=true should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • If the QRTR protocol support is required, the additional -Dqrtr=true should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • The suspend/resume handling is enabled by default. In order to disable it, the additional -Dsystemd_suspend_resume=false should be given.
  • The gtk-doc documentation is disabled by default. In order to enable it, the additional -Dgtk_doc=true switch should be given.
  • The GObject introspection support for the libmm-glib library is enabled by default. In order to disable it, the additional -Dintrospection=false switch should be given.
  • The bash-completion support is enabled by default. In order to disable it, the additional -Dbash_completion=false switch should be given.
  • The default build type in meson if none explicitly specified is debug, which means debug symbols are included and optimization is fully disabled. The --buildtype=release switch can be used to remove debug symbols and to enable optimization level to the maximum.

An example project build using all the above optional switches could be:

  $ meson setup build                     \
      --prefix=/usr                       \
      --sysconfdir=/etc                   \
      --libdir=/usr/lib/x86_64-linux-gnu  \
      --buildtype=release                 \
      -Dqmi=true                          \
      -Dmbim=true                         \
      -Dqrtr=true                         \
      -Dsystemd_suspend_resume=false      \
      -Dgtk_doc=true                      \
      -Dintrospection=false               \
      -Dbash_completion=false
  $ ninja -C build

Installing

The installation on the prefix selected during meson setup can be done with the following command:

  $ sudo ninja -C build install

Please note that the command above will install the library in the system default path for libraries, possibly overwriting any previous libmm-glib library that may already exist from a package manager installed package. See the FAQ section for comments on how to install in /usr/local instead.

Uninstalling

If you have manually installed the project with the steps above, it can be uninstalled in the same way:

  $ sudo ninja -C build uninstall

If the manual install overwrote the package manager installed files, it is suggested to force a re-install of the corresponding packages at this point, so that the system is not left with missing files.

2.2 - Building ModemManager 1.18 or earlier using GNU autotools

How to build and install the ModemManager daemon and libraries using GNU autotools.

The last stable series with support for building with the GNU autotools suite is 1.18. All the new stable series after 1.18 will exclusively use the meson build system.

Building from a release source tarball

The basic build and installation of the project can be done from an official release source tarball, in the following way:

  $ wget https://www.freedesktop.org/software/ModemManager/ModemManager-1.18.0.tar.xz
  $ tar -Jxvf ModemManager-1.18.0.tar.xz
  $ cd ModemManager-1.18.0
  $ ./configure --prefix=/usr --sysconfdir=/etc
  $ make

Optional switches

Additional optional switches that may be given to the configure command above would be:

  • In Debian/Ubuntu systems the default location for libraries depends on the architecture of the build, so instead of the default /usr/lib path that would be in effect due to --prefix=/usr, the user should also give an explicit --libdir path pointing to the correct location. E.g. on a 64bit Ubuntu/Debian build, the user would use --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu.
  • If the MBIM protocol support is required, the additional --with-mbim should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • If the QMI protocol support is required, the additional --with-qmi should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • If the QRTR protocol support is required, the additional --with-qrtr should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • If the suspend/resume handling is required, the additional --with-suspend-resume=systemd should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies.
  • If the documentation should be rebuilt, the additional --enable-gtk-doc switch should be given. Omitting this switch will imply auto-detecting whether the documentation can be rebuilt with the already installed dependencies.
  • If the introspection support for the libmm-glib library should be included in the build, the additional --enable-introspection switch should be given. Omitting this switch will imply auto-detecting whether the introspection can be built with the already installed dependencies.
  • When developing changes to the project or debugging issues, it is recommended to build with debug symbols so that running the program under gdb produces useful backtrace information. This can be achieved by providing user compiler flags like these: CFLAGS="-ggdb -O0"

An example project build using all the above optional switches could be:

  $ ./configure                          \
      --prefix=/usr                      \
      --sysconfdir=/etc                  \
      --libdir=/usr/lib/x86_64-linux-gnu \
      --with-qmi                         \
      --with-mbim                        \
      --with-suspend-resume=systemd      \
      --enable-gtk-doc                   \
      --enable-introspection             \
      CFLAGS="-ggdb -O0"
  $ make

Running ./configure --help will show all the possible switches that are supported.

Building from a git checkout

When building from a git checkout, there is one single additional step required to build the project: running the included autogen.sh in order to setup the GNU autotools project and generate a configure script:

  $ git clone https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git
  $ cd ModemManager
  $ NOCONFIGURE=1 ./autogen.sh
  $ ./configure --prefix=/usr --sysconfdir=/etc
  $ make

The same optional switches may be given to the configure script when building from a git checkout.

Installing

The installation on the prefix selected during configure can be done with the following command:

  $ sudo make install

Please note that the command above will install the library in the system default path for libraries, possibly overwriting any previous libmm-glib library that may already exist from a package manager installed package. See the FAQ section for comments on how to install in /usr/local instead.

Location of the DBus service files

By default the DBus service files provided by ModemManager are installed under <prefix>/share/dbus-1/system.d/. If the user uses the default /usr/local prefix instead of the suggested /usr prefix, the DBus service files would be installed in a path that is completely ignored by DBus. If the service files haven’t changed with respect to the one provided by the package manager, this issue can probably be ignored.

Location of the udev rules

By default the udev rules provided by ModemManager are installed under /lib/udev/rules.d/, out of the prefix provided by the user. If the user uses the default /usr/local prefix instead of the suggested /usr prefix, the udev rules would not change location. Changing the location of where the udev rules are installed so that the package manager provided ones are not overwritten can be done e.g. with --with-udev-base-dir=/usr/local/lib/udev/rules.d, but note that these rules will not be actively used by udev as they are not installed in a standard path.

Location of the systemd init files

By default the systemd init files provided by ModemManager are installed under the path specified by the systemd library pkg-config file in the systemdsystemunitdir variable, e.g. /lib/systemd/system/. This path is completely independent to the prefix provided by the user. Changing the location of where the systemd init files are installed so that the package manager provided ones are not overwritten can be done e.g. with --with-systemdsystemunitdir=/usr/local/lib/systemd/system, but note that the init file will not be actively used by systemd as it is not installed in a standard path.

Uninstalling

If you have manually installed the project with the steps above, it can be uninstalled in the same way:

  $ sudo make uninstall

If the manual install overwrote the package manager installed files, it is suggested to force a re-install of the corresponding packages at this point, so that the system is not left with missing files.

3 - Debugging

Debugging issues with the ModemManager daemon

Daemon debug logs

Gathering debug logs of both NetworkManager and ModemManager daemons involves several steps. Although these daemons allow to configure the log level manually while running, some of the issues to debug may require a full reboot of both processes, so the steps below try to cover the most generic case.

Note that the debug logs may contain sensitive information (e.g. PIN number, APN settings, SMS contents). Feel free to remove that information when providing logs to the developers, specifying which was the information removed.

The NetworkManager daemon debug logs would only be required to analyze connectivity related problems. If the issue is unrelated to data connectivity, just the ModemManager daemon debug log should be enough.

When using systemd

Mask and stop the services:

$> sudo systemctl disable NetworkManager ModemManager
$> sudo systemctl stop NetworkManager ModemManager

Manually run with debug enabled:

$> sudo /usr/sbin/ModemManager --debug
$> sudo /usr/sbin/NetworkManager --debug --log-level=DEBUG

Now, reproduce your issue, and gather debug logs. Use Ctrl+C to stop both processes.

Then, unmask the services and start them:

$> sudo systemctl enable NetworkManager ModemManager
$> sudo systemctl start NetworkManager ModemManager

When not using systemd

If you are not using systemd, you can avoid getting the processes automatically launched (e.g. by DBus activation) by moving the program files to another path:

$> sudo mv /usr/sbin/NetworkManager /
$> sudo mv /usr/sbin/ModemManager /
$> sudo killall -TERM NetworkManager
$> sudo killall -TERM ModemManager

Manually run with debug enabled (using the new path):

$> sudo /ModemManager --debug
$> sudo /NetworkManager --debug --log-level=DEBUG

Now, reproduce your issue, and gather debug logs. Use Ctrl+C to stop both processes.

Finally, recover the original places for the program files:

$> sudo mv /ModemManager /usr/sbin/
$> sudo mv /NetworkManager /usr/sbin/

qmi-proxy or mbim-proxy debug logs

Sometimes debugging problems in ModemManager requires not only the daemon’s own debug log, but also the verbose logs of the qmi-proxy or mbim-proxy processes, which are the ones synchronizing the access to the QMI or MBIM control ports. In order to gather these additional logs, explicitly kill the processes and manually launch them in a separate terminal BEFORE running ModemManager --debug:

$> sudo killall mbim-proxy
$> sudo /usr/libexec/mbim-proxy --no-exit --verbose

$> sudo killall qmi-proxy
$> sudo /usr/libexec/qmi-proxy --no-exit --verbose

Usually only one of these proxies is used, there is no need to debug both at the same time.

4 - FCC unlock procedure

FCC unlock procedure integration in ModemManager.

Short summary

Since ModemManager 1.18.4, the following applies:

  • The FCC unlock procedure is no longer enabled by default.
  • Laptop vendors may provide custom packages to enable their own FCC unlock scripts in ${libdir}/ModemManager/fcc-unlock.d.
  • Users may manually enable the ModemManager-provided FCC unlock scripts in ${sysconfdir}/ModemManager/fcc-unlock.d.
  • Distribution packages should install the ModemManager-provided FCC unlock scripts in ${datadir}/ModemManager/fcc-unlock.available.d/
  • Distribution packages should not enable the ModemManager-provided FCC unlock scripts in either ${sysconfdir}/ModemManager/fcc-unlock.d or ${libdir}/ModemManager/fcc-unlock.d.

The procedure for users to manually enable all ModemManager-provided FCC unlock scripts in a system where ${datadir} is /usr/share and ${sysconfdir} is /etc would be:

 $ sudo ln -sft /etc/ModemManager/fcc-unlock.d /usr/share/ModemManager/fcc-unlock.available.d/*

What is the FCC lock?

The FCC lock is a software lock integrated in WWAN modules shipped by several different laptop manufacturers like Lenovo, Dell, or HP. This locks prevents the WWAN module from being put online until some specific unlock procedure (usually a magic command sent to the module) is done.

If the specific unlock procedure is not done, any attempt to enable the radio with any kind of protocol will fail:

  • AT+CFUN=1 will fail, likely with just an ERROR response.
  • QMI DMS Set Operating Mode (ONLINE) will fail, likely with an Invalid transition error.
  • MBIM Radio State (ON) will fail, likely with an Operation not allowed error.

The purpose of this lock is, according to the manufacturers, to have a way to bind the WWAN module to a specific laptop, so that the whole bundle of laptop+module can go through the FCC certification process for radio-enabled devices in the USA. This lock has no other known purpose out of the US regulation.

The FCC lock is also part of a mutual authentication attempt between module and laptop:

  • The laptop BIOS comes with an allowlist of modules that can be installed in the laptop.
  • The WWAN module comes with a FCC lock that should be unlocked by approved laptops only.

Laptop manufacturers should in theory provide a custom FCC unlock tool so that users can use the modules, but the reality is sometimes far from ideal:

  • The unlock tools may be provided only for Windows, if the laptops were not FCC certified to be used in GNU/Linux distributions.
  • The unlock tools are usually provided as proprietary binary programs that are non-auditable and still need to be run as root in the system.
  • The unlock tools will perform system checks to detect which kind of laptop the module is installed in, and if it is not one of the laptops certified by the vendor for use under GNU/Linux, the tool may not unlock the modem, even if the same setup can be used in Windows.
  • The unlock tools sometimes fail to be available for Linux users by the time the laptops are ready to be sold.

FCC unlock procedures in ModemManager < 1.18.4

When the first FCC unlocked modems were shipped in Dell laptops sometime around 2015, users of GNU/Linux distributions started to report not being able to use their WWAN modules. These modems were rebranded Sierra Wireless devices, and surprisingly, using the Sierra Wireless provided kernel drivers the modules were unlocked successfully. This lead to finding the QMIDMSSWISetFCCAuth() operation (DMS 0x555F) in the Sierra SDK, which was successfully reverse engineered into libqmi 1.12.4.

The FCC unlock logic done for these modules was added into ModemManager 1.4.4 for all QMI capable devices, just attempting to run it any time we found the attempt to put the module online failed.

In 2018, Dell included newer FCC locked modems, like the Foxconn rebranded DW5821e, in their laptops. Dell also provided a Windows unlock tool (DW5821e and DW5829e Click Cust Kit), and likely some built-in unlock tool hidden in the Ubuntu-based preinstallations they shipped in the laptops when sold with GNU/Linux. During this time, there were some attempts to reverse engineer the unlock procedure using a USB monitoring capture from Windows when running the Cust Kit tool, but none of them seemed to be usable for some reason.

Fast forward to 2021, when Lenovo shipped the newest X1 Nano and Carbon Gen9 laptops with new FCC locked modules, and users started to report the same issues again. These laptops were released with 3 different approved modules: Foxconn SDX55, Quectel EM120, and Fibocom L860. By the time the first SDX55 modules were available there was still no unlock tool provided by Lenovo, so there was not much anyone could do. But the SDX55 was a Foxconn module, same as the DW5821e for which the Dell Cust Kit tool was reverse engineered, and so users tried that same procedure that never worked with the DW5821e, just to find that it worked fine with the SDX55. This unlock procedure was included in libqmi 1.28.6, and integrated for automatic unlocking in ModemManager 1.16.6.

Not much later, users started to report about the Quectel EM120 module being locked. A user of this module was able reverse engineer the Lenovo-provided lenovo-wwan-dpr tool and discover the magic MBIM command that was being sent in this case. This procedure has not been integrated for automatic unlock in any ModemManager version.

Whether to automatically unlock or not the modules in ModemManager

When the first FCC unlock procedure was reverse engineered for the rebranded Sierra Wireless modules, there was not much discussion on whether the procedure should be run or not by ModemManager. It was obviously defeating the purpose of the laptop manufacturer, but so was the Sierra Wireless driver source provided by Sierra Wireless themselves. If they were doing it, why should ModemManager not do it?

The picture with the new WWAN modules in Lenovo laptops is completely different, though. The FCC unlock procedure for the EM120 was reverse engineered from the Lenovo-provided lenovo-wwan-dpr tool, which performs not only the FCC unlock, but also dynamic power reduction based on sensors in the laptop. This means that the actual magic command used to unlock the module may be somehow related to some SAR level defaults configured in the WWAN module, and as we don’t have the full picture of what it does or doesn’t, it can be considered a bit risky to perform the automatic unlock unconditionally. The same reasoning would apply for the Foxconn SDX55, for which not even a Lenovo provided tool was used to reverse engineer the unlock procedure. The sad truth is that only the laptop vendors and modem manufacturers know what those commands are really doing, and they may be doing more than FCC unlocking the modules. If the procedures are related in any way to SAR levels and dynamic power reduction, ModemManager should better not automatically unlock these modules.

This discussion went on for several months, both publicly in gitlab issues and mailing list, and privately via emails and calls with the laptop vendors, modem manufacturers and other key members of the community. After much thought a clear way forward was decided, that would hopefully meet halfway of both sides: ModemManager will keep on providing support for the known FCC unlock procedures, but no longer automatically: the user must install and select the FCC unlock procedure needed in the specific laptop being used.

FCC unlock procedures in ModemManager >= 1.18.4

Since release 1.18.4, the ModemManager daemon no longer automatically performs the FCC unlock procedure by default. The user must, under their own responsibility, enable the automatic FCC unlock as shipped by ModemManager.

ModemManager ships several scripts installed under ${datadir}/ModemManager/fcc-unlock.available.d, and named as vid:pid with either the PCI or USB vendor and product IDs. E.g. in a system where ${datadir} is /usr/share:

  • For the HP 820 G1 (EM7355): /usr/share/ModemManager/fcc-unlock.available.d/03f0:4e1d
  • For the Dell DW5570 (MC8805): /usr/share/ModemManager/fcc-unlock.available.d/413c:81a3
  • For the Dell DW5808 (MC7355): /usr/share/ModemManager/fcc-unlock.available.d/413c:81a8
  • For the Lenovo-shipped EM7455: /usr/share/ModemManager/fcc-unlock.available.d/1199:9079
  • For the Foxconn SDX55: /usr/share/ModemManager/fcc-unlock.available.d/105b:e0ab
  • For the Quectel EM120: /usr/share/ModemManager/fcc-unlock.available.d/1eac:1001

These scripts in ${datadir} are not automatically used by ModemManager. In order for ModemManager to automatically attempt a specific FCC unlock procedure, the user must create a link to the script from ${datadir}/ModemManager/fcc-unlock.available.d into the ${sysconfdir}/ModemManager/fcc-unlock.d directory. E.g. in a system where ${datadir} is /usr/share and ${sysconfdir} is /etc:

 $ sudo ln -sft /etc/ModemManager/fcc-unlock.d /usr/share/ModemManager/fcc-unlock.available.d/<vid>:<pid>

ModemManager will only use the unlock script required for the specific vid:pid the module exposes, so users may also choose to link all the files from ${datadir}/ModemManager/fcc-unlock.available.d into ${sysconfdir}/ModemManager/fcc-unlock.d. E.g. in a system where ${datadir} is /usr/share and ${sysconfdir} is /etc:

 $ sudo ln -sft /etc/ModemManager/fcc-unlock.d /usr/share/ModemManager/fcc-unlock.available.d/*

It is suggested that GNU/Linux distributions do not ship these FCC unlock scripts enabled in the ${sysconfdir}/ModemManager/fcc-unlock.d directory themselves, for the same reasons that ModemManager does not to perform the automatic unlock unconditionally.

The ${sysconfdir}/ModemManager/fcc-unlock.d path should be exclusively used for links or programs manually installed by the user.

The scripts shipped by ModemManager use either mbimcli or qmicli to perform the raw FCC unlock procedure. The user should make sure those tools are installed in the system, as they are not direct dependencies of ModemManager in any way. E.g. in Debian/Ubuntu systems, these tools are provided by the libmbim-utils and libqmi-utils packages.

Integration with third party FCC unlock tools

Laptop vendors and modem manufacturers may also provide their own FCC unlock tools, e.g. running their own proprietary binary programs to perform the unlock in the safest way they know. These tools may be packaged for each distribution, and should be installed in ${libdir}/ModemManager/fcc-unlock.d.

The third party FCC unlock tools will allow an easy integration of the procedure with ModemManager, so that the unlock is performed only when required to do so (when attempting to go online) and not at random times (which would make the state of the modem cached by ModemManager inconsistent).

Third party FCC unlock scripts or programs should consider the same limitations as imposed to the ModemManager shipped ones:

  • Must be owned by the root user.
  • Must be readable and executable by the owner exclusively and not setuid.
  • Will receive the full modem DBus path as first argument, followed by the control port names (without /dev prefix) of the modem to unlock.
  • Must not launch processes on background; i.e. these are not service management scripts.
  • Must run in less than 5 seconds, or otherwise they will be killed by ModemManager.
  • Must return 0 on success.

Once the tool is run by ModemManager, the daemon will attempt again to bring the modem into online power state using the protocol specific messages. If this operation fails again, the FCC unlock procedure will not be automatically tried any more.

The ${libdir}/ModemManager/fcc-unlock.d path should be exclusively used for links or programs installed by third party packages.

5 - WWAN device types

Types of WWAN devices and how they are exposed in the system

Types of devices and how they are exposed in the system

ModemManager can interact with almost every type of mobile broadband modem that exposes at least one control port. Devices without control ports (e.g. some USB dongles that expose a net port exclusively) aren’t supported by ModemManager.

USB devices

USB devices are the most common type of devices, and come in very different form factors. USB dongles that can be connected to the physical USB port of the computer are one type, but modules connected in miniPCIe or M.2 slots are also very common, especially in embedded systems and laptops.

USB device types 1

USB device types 2

A device enumerated in the USB bus is able to expose in the system multiple ports, so there is no limitation on the number of control ports or data ports that can be found. USB modems with multiple control ports are very common, e.g. allowing different operations to be run in parallel in the different ports; but modems with multiple data ports also exist, e.g. in order to allow connections to multiple APNs separately without the need of complex multiplexing setups

The types of ports that are expected on this type of device are:

  • Serial ports (e.g. ttyUSB0, ttyACM0…).
  • Network ports (e.g. wwan0, usb0, eth0…).
  • QMI or MBIM control ports (e.g. cdc-wdm0…)
  • WWAN subsystem QMI or MBIM control ports (e.g. wwan0mbim0, wwan0qmi0).

Devices that require USB mode switching

Sometimes the USB devices boot by default on a non-modem USB layout, e.g. exposing themselves as a USB disk. This was very common with USB dongles (e.g. from Huawei, ZTE…) that required special drivers to be installed in the Windows operating system; the USB disk exposed by the dongle would provide the tool to install that driver.

In Linux based systems the users expect the devices to work without requiring any additional driver installation, and to achieve that there are tools like usb-modeswitch that are able to automatically switch the devices into a valid modem USB layout without any manual user intervention.

Devices with multiple USB configurations

There are devices (e.g. a lot of Foxconn or Huawei modules) that expose multiple USB configurations by default, each of them providing a different layout of USB interfaces. One configuration could for example include a MBIM control port and a network interface, another configuration could include an AT port and a NCM network interface, and so on.

The devices will by default be exposed by the kernel in the USB configuration that best matches a generic layout. E.g. if a device exposes both MBIM and QMI layouts in different configurations, the MBIM one will always be preferred because it’s considered more generic than the QMI one. Sometimes this is not enough, though, as devices with NCM and MBIM layouts are both generic, and the kernel may choose the NCM over the MBIM one by default, while the MBIM one is really preferred in general. In order to cope with these cases, the usb-modeswitch tool allows to automatically select the MBIM configuration regardless of what others are available in the USB device.

Devices with support for multiple layouts via control port configuration

There are devices (e.g. a lot of Sierra Wireless modules) that allow selecting the USB layout in order to for example include additional AT ports on an otherwise bare QMI and net port layout, or even completely change the layout from a QMI based one to a MBIM based one.

RS232 devices

RS232 devices are still used in certain setups due to their simplicity, but they are mostly phased out for USB modems that are able to expose multiple ports via a single USB connection.

There are two main ways to have these devices integrated into the system: either using a real physical RS232 connection or otherwise using a USB to RS232 adapter/converter. In both those cases, the devices will end up exposing a single serial port in the system, which ModemManager will use first for control (AT) and then for data (PPP).

RS232 device types

Unlike USB modems, the RS232 modems require very explicit settings agreed beforehand with the host in order to properly talk to them (e.g. baudrate, number of stop bits, flow control settings…). Any misconfiguration in any of these settings (either in the modem itself or in the host) could make the communication impossible.

The types of ports that are expected on this type of device are:

  • Platform serial ports (e.g. ttyS0…).
  • USB serial ports (e.g. ttyUSB0…).

PCI devices

PCIe devices are much more complex and advanced than most USB devices, because they require a tighter integration with the host system. Among other things, this allows them to have much higher data throughputs during an ongoing connection than what’s achievable with USB 3.0 and USB 2.0.

Unlike the USB case, PCIe devices do not expose multiple optional configurations or layouts. The device has preconfigured in the firmware the list of channels to be accessible by the kernel drivers. There may be some configurability supported, but it is not as common as with USB devices.

These devices come in the same form factor as miniPCIe or M.2 USB modems, but using the PCI bus instead of the USB bus. A device working in PCIe mode will not work as a USB device, and a device working in USB mode will not work as a PCIe device. Some manufacturers allow changing the PCIe/USB mode via software (e.g. with proprietary AT commands) and some others allow changing it via hardware (e.g. by changing the voltage level in an input GPIO).

PCIe devices are integrated in the upstream Linux kernel using the WWAN subsystem introduced in kernel 5.13. This subsystem also allows the kernel to explicitly define which control protocol is expected to be used in the port, so there is no need for custom port type hints in ModemManager.

The types of ports that are expected on this type of device are:

  • Network ports (e.g. wwan0).
  • WWAN subsystem AT, QMI or MBIM control ports (e.g. wwan0mbim0, wwan0qmi0, wwan0at0…).

PCI device types

Qualcomm SoCs

The case of Qualcomm SoCs is quite different from the usual modem management case because there is no external device connected to the host, the modem is integrated in the host system itself, and therefore requires different ways to communicate with it.

Modem control operations through nodes in the QRTR bus are supported, as well as through character devices exposed by the WWAN subsystem built on top of the rpmsg subsystem. Depending on the capabilities of the SoC one method or the other will be used; older SoCs have rpmsg support exclusively, others have both rpmsg and QRTR (but the latter not for modem management), and newer SoCs have full support for QRTR (including modem management).

The network interface support in Qualcomm SoCs is also a bit different, because it is required to bind a given data connection to a specific network interface explicitly. In SoCs using the bam-dmux kernel driver, there are usually a fixed number of network interfaces already exposed in the system, while in newer ipa driver based setups it is required to instantiate new virtual network interfaces when a connection is being brought up.

Qualcomm SoC device types

The types of ports that are expected on this type of device are:

  • Network ports (e.g. rmnet_ipa0).
  • WWAN subsystem AT or QMI control ports (e.g. wwan0qmi0, wwan0at0, in QC MSM8916).
  • QRTR nodes accessible via the QRTR bus (e.g. in QC 7cG3). These control ports do not expose any character device in /dev, they are only accessible via AF_QIPCRTR sockets.

Hints to investigate device layouts

USB devices

The devices that are exposed in the USB bus can be inspected quickly using the tree view of the lsusb command which includes information about the available interfaces in the currently selected configuration.

$ lsusb --tree

Once the device to investigate has been identified, the lsusb command can also be used to query the whole set of details for the USB device, including which are all the USB configurations it has (even if only one of them is currently selected).

$ lsusb -v -d <vid:pid>

Using the usb-devices command is also useful as it provides information of which kernel driver is actually managing each of the ports of the device. In this case, though, the command only shows information about the current USB device configuration and layout.

$ usb-devices

The USB devices and each of their control and data ports will get entries under sysfs, and the device-wide sysfs entry is what ModemManager uses to bind all ports of a given modem together in the same logical object.

PCI devices

The lspci command can be used in a similar way to the lsusb one but for PCI devices instead of USB devices.

$ lspci -t
$ lspci -v

QRTR capable devices

For Qualcomm devices that are accessible through the QRTR subsystem, several command line tools are available in Bjorn Andersson’s github repository:

$ qrtr-lookup

Udev device traversal

Running udevadm to investigate how udev sees a given port is always very handy, especially when writing new udev rules.

Querying all information for a specific device can be done as follows:

$ sudo udevadm info -p /sys/class/<subsystem>/<name>

If new udev rules were added, they should be visible in the output of the previous command.

Querying all the attributes for a device and all its parents (if any) can be done as follows:

$ sudo udevadm info -a /sys/class/<subsystem>/<name>

The previous query will dump multiple lines with different attributes that can be used as-is in custom udev rules.

6 - Port and device detection

How ModemManager detects ports and devices

Udev

The ModemManager daemon does not attempt to detect by itself which modems are available in the system. It instead relies on the udevd daemon and the port addition and removal events produced whenever the port states change in the kernel.

ModemManager also uses an explicit query on udev during bootup in order to know which ports were detected and exposed before the daemon was ready to receive new addition and removal events.

Only per-port events are monitored; i.e. explicit port addition and removals. Other events associated with the modem device, like full device addition or removal notifications or per-interface notifications (in USB devices for example) are ignored. On a new device detection, this logic will therefore receive one addition event for each port exposed by the modem.

The ModemManager device detection procedure keeps some timeouts in place so that the logic stops waiting for more ports to be notified after some time. This logic assumes that new port additions in a given device happen in a timely manner, which is the most usual case; if for any reason one of the ports ends up being notified much later than the others, the port may end up fully ignored.

Monitored subsystems

Each plugin in ModemManager registers a list of subsystems it is interested in monitoring. When the available plugins are loaded, the daemon will therefore compile a list of all subsystems that the registered plugins are requesting.

The subsystems usually monitored are:

  • tty subsystem: where all serial ports are exposed (e.g. ttyS0, ttyUSB0, ttyACM0, ttyHS0…).
  • usbmisc subsystem: where the cdc-wdm ports (either QMI, MBIM or AT) are exposed.
  • net subsystem: where all the network ports are exposed.
  • wwan subsystem: where all control ports for PCIe devices and some Qualcomm SoCs are exposed. This subsystem also exposes control ports for QMI and MBIM USB devices, in addition to the original cdc-wdm ports in the usbmisc subsystem, but these are considered duplicates and ignored by ModemManager.
  • qrtr subsystem: This is not a real device subsystem in the kernel, but ModemManager uses this to reference modem management nodes exposed in the Qualcomm specific QRTR bus. Given that these nodes don’t have any exposure in sysfs, there is no way to bind udev tags to them.

udev tags

The tags in udev have several different primary purposes, but in general they can be seen as a way ModemManager uses to configure device specific behaviors.

ModemManager ships and documents several generic udev tags that can be applied to any type of device, and several plugin-specific tags that are meaningful to a set of devices or to a specific manufacturer. The generic udev tags are included and explained in the ModemManager API documentation.

Generic candidate ports and grouping rules

These are rules that allow ModemManager to identify which devices should be detected and probed as possible cellular devices.

Generic port or device ignoring rules

These are rules that allow the user to deny access to certain ports on a given device, or to full devices.

Generic port type hint rules

These are rules that allow the probing logic of ModemManager to decide faster what kind of protocol is expected in a given port, as well as specifying behavior that is expected in that port (e.g. in AT ports there may be one port that is targeted to be used for PPP and not for general control).

Generic RS232 port configuration rules

Plugin-specific device identification rules

Certain modems, like the Ericsson MBM modules, require explicit tags to identify them as being modems that can be controlled by ModemManager. This is usually required with manufacturers that ship many types of different devices under the same USB or PCI vendor identification.

Feature configuration/disabling rules

There are cases where some specific features are non-functional in a given device, or even worse, they may end up triggering irrecoverable firmware crashes. When they are identified, feature specific udev tags are set in the relevant modem ports so that ModemManager knows it should avoid using that feature. Notable examples include the AT^NDISDUP support in Huawei devices or the AT+CPOL based management in multiple plugins.

Adding new udev tags

Users can specify udev tags themselves, by creating new rules files that are installed (usually) under /lib/udev/rules.d. There aren’t many requirements to this user rules files, but the existing ones are important:

  • The rules file names should be prefixed by either 78-mm- or 79-mm-. This is so that the user-defined rules are processed after the generic rules (which are all installed as 77-mm-) and before the candidate rules (in the 80-mm- prefixed rules file).
  • Even though official udev rules allow running multiple actions matching a set of rules, the ModemManager udev rules always process one single action on every line. This is a limitation of the custom udev rule parser used in openwrt.
  • Following the same pattern as the ModemManager udev rules, the rules should be run on add, change, move and bind ACTIONs.
  • Port specific tags should be applied to specific ports (e.g. USB ports identified by the USB interface number).
  • Device specific tags should be applied to all control ports in the same way or to the full device if there is one in the sysfs tree.
  • Beware of SUBSYSTEMS vs SUBSYSTEM, or ATTRS vs ATTR and so on. One (without the trailing S) matches a specific device in the device hierarchy, while the other (with the trailing S) matches a device and all its parents on the hierarchy. For example, a TTY port in a USB device will definitely match SUBSYSTEMS==”usb” (because a direct parent of the TTY port will be the physical USB device) but it will also match SUBSYSTEMS==”pci” (because the USB controller where the device is managed is hanging off the PCI bus).
  • Writing udev rules is tricky, so following what the existing rules do is always a good approach.

A new set of rules specified by a user could look like this:

$ cat /lib/udev/rules.d/78-mm-my-rules.rules
ACTION!="add|change|move|bind", GOTO="mm_my_rules_end"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1234", GOTO="mm_my_rules"
GOTO="mm_my_rules_end"

LABEL="mm_my_rules"
# Store interface number in an env var
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", \
  ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
# USB iface #0 will be primary AT port
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="abcd", ENV{.MM_USBIFNUM}=="00", \
  SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
# USB iface #1 will be PPP port
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="abcd", ENV{.MM_USBIFNUM}=="01", \
  SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PPP}="1"
LABEL="mm_my_rules_end"

Once the new file in the filesystem is created, validating whether the tags are correctly applied would involve two steps:

  • First, reloading and applying the rules:
$ sudo udevadm control –reload
$ sudo udevadm trigger
  • Second, showing which tags are available in the target port:
$ sudo udevadm info -p /sys/class/tty/ttyUSB0

Hotplug in Openwrt

There is no udev in openwrt, so ModemManager has an alternative way to get notified of the port addition and removal events. In this operating system, the ModemManager package installs a set of hotplug scripts that are called by the openwrt init system whenever port state changes happen in the kernel. As in the case of udev, ModemManager processes per-port events and determines at runtime which ports should be aggregated into the same modem object.

During ModemManager bootup, the init script in openwrt will ensure that all the port addition and removal events that happened before the daemon was ready to process them are properly queued up so that they get processed in the same order as they originally happened.

There is also no udev rules processing in openwrt, and so ModemManager does its own processing of the rules in a way that should be mostly equivalent to how udev processes them. The built-in udev processor in ModemManager is not as complete as the original one, so adding custom rules may not always work, unless the new rules are equivalent to other existing ones and therefore implicitly supported.

Port selection filters in ModemManager

The ModemManager daemon will not probe all possible control ports it finds, as doing so would break a lot of non-modem ports that devices expose as TTYs. But this was not the default behavior in older releases, and the ModemManager daemon would end up poking serial ports at will while breaking the communication attempted by the real user processes of those serial ports. Users reported issues where the daemon poked Arduino serial ports, GPS devices, or even screen readers for the visually impaired. A lot of effort was put into improving this situation, which led to a series of changes during several years to reach the state we have now.

  • Until release 1.8.0, the default behavior of ModemManager was to by default attempt to probe TTY ports unless they were deny-listed explicitly. The project would maintain a large list of udev rules identifying devices that are not modems but still exposed TTYs, but (no surprise) keeping that list up to date was a mess and very error prone.
  • In release 1.8.0, a new set of filter types was introduced:
    • The old behavior, where ports were probed unless explicitly flagged with a specific udev tag, was still the default one and the filter was named “default”. With this filter, platform serial ports (e.g. real RS232 physical ports in the system) could be automatically probed if a manual scan operation was triggered.
    • “whitelist-only” filter, in which ModemManager would only probe control ports if they were explicitly flagged with the ID_MM_DEVICE_PROCESS udev tag.
    • “strict” , in which ModemManager would by default not probe the TTY ports unless it knew with a high amount of certainty that the port was a modem port; e.g. with rules checking for AT protocol support definitions in ttyACM ports, looking at which kernel drivers are in use, or even based on port type hint rules already defined in ModemManager. The option to request a manual scan was also removed when this filter was used. Platform RS232 ports need to be explicitly flagged (e.g. with ID_MM_DEVICE_PROCESS) to be probed.
    • “paranoid” filter was equal to the “strict” mode but also applied the list of denied devices that the “default” filter was based on.
  • In release 1.14.0, ModemManager would switch to use the “strict” filter by default if no other one was explicitly selected. The old “default” filter was renamed to “legacy” and considered deprecated.
  • In release 1.18.0 the “legacy” and “paranoid” filter types were fully removed, along with all the lists of udev rules for denied devices.
  • In release 1.20.0 the “whitelist-only” filter was renamed to “allowlist-only”, while deprecating the older name.

Since 1.20.0 only the “strict” and “allowlist-only” filter types are used, defaulting to “strict” if none is explicitly selected. These filters will be mapped to more detailed rules applied by ModemManager upon device detection.

E.g. when the “strict” filter is selected, all the heuristics to detect cellular device ports are enabled, as seen in the daemon debug logs:

[filter] created
[filter]   explicit allowlist:         yes
[filter]   explicit blocklist:         yes
[filter]   plugin allowlist:           yes
[filter]   qrtr devices allowed:       yes
[filter]   virtual devices forbidden:  yes
[filter]   net devices allowed:        yes
[filter]   usbmisc devices allowed:    yes
[filter]   rpmsg devices allowed:      yes
[filter]   wwan devices allowed:       yes
[filter]   tty devices:
[filter]       platform driver check:    yes
[filter]       driver check:             yes
[filter]       cdc-acm interface check:  yes
[filter]       with net check:           yes
[filter]       default:                  forbidden

When the “allowlist-only” filter is selected, the amount of rules enabled is limited to only one, the explicit allowlist:

[filter] created
[filter]   explicit allowlist:         yes
[filter]   explicit blocklist:         no
[filter]   plugin allowlist:           no
[filter]   qrtr devices allowed:       no
[filter]   virtual devices forbidden:  no
[filter]   net devices allowed:        no
[filter]   usbmisc devices allowed:    no
[filter]   rpmsg devices allowed:      no
[filter]   wwan devices allowed:       no
[filter]   tty devices:                no

Worth noting, ModemManager does not touch the network ports of a modem in any way. During the daemon startup there isn’t a strict list of rules to decide whether a network port is part of a modem device or not, the network ports are seen as additional ports in a modem if other control ports are found and validated.

Example device detection logs

The following log shows the device detection phase of a device during ModemManager bootup, with comments about what is happening at each moment.

// ttyUSB0 is detected via udev, a set of port identification
// parameters are preloaded.
[34.337] [ttyUSB0] port contents loaded:
[34.338] [ttyUSB0]   bus: usb
[34.339] [ttyUSB0]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.2
[34.340] [ttyUSB0]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.340] [ttyUSB0]   driver: qcserial
[34.341] [ttyUSB0]   vendor: 1199
[34.341] [ttyUSB0]   product: 9091
[34.342] [ttyUSB0]   revision: 0006
[34.343] [base-manager] adding port ttyUSB0 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.2/ttyUSB0/tty/ttyUSB0

// The currently active filter flags the port as allowed and specifies
// why. In this case, the specific vid (1199) is allowlisted by the
// Sierra plugin.
[34.359] [filter] (tty/ttyUSB0) port allowed: device is allowlisted by plugin (vid)

// ttyUSB0 is the first port detected in the modem device.
[34.360] [base-manager] port ttyUSB0 is first in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// A new support task is created for the device, which will determine
// which plugin takes care of managing it. In this case, the task is
// not yet launched because there is a “minimum wait time” that
// ModemManager waits before starting the probing tasks (a few
// seconds).
[34.373] [plugin-manager] task 0: new support task for device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.391] [plugin-manager] task 0: port grabbed: ttyUSB0
[34.393] [plugin-manager] task 0,ttyUSB0: new support task for port
[34.393] [plugin-manager] task 0,ttyUSB0: deferred until min wait time elapsed

// ttyUSB1 is detected via udev, a set of port identification
// parameters are preloaded.
[34.398] [ttyUSB1] port contents loaded:
[34.398] [ttyUSB1]   bus: usb
[34.398] [ttyUSB1]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.3
[34.398] [ttyUSB1]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.399] [ttyUSB1]   driver: qcserial
[34.399] [ttyUSB1]   vendor: 1199
[34.399] [ttyUSB1]   product: 9091
[34.399] [ttyUSB1]   revision: 0006
[34.399] [base-manager] adding port ttyUSB1 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.3/ttyUSB1/tty/ttyUSB1
[34.402] [filter] (tty/ttyUSB1) port allowed: device is allowlisted by plugin (vid)

// ttyUSB1 is added as an additional port to the already existing
// device.
[34.404] [base-manager] additional port ttyUSB1 in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// The support task is notified about the new ttyUSB1 port, but still
// deferred.
[34.405] [plugin-manager] task 0: port grabbed: ttyUSB1
[34.407] [plugin-manager] task 0,ttyUSB1: new support task for port
[34.407] [plugin-manager] task 0,ttyUSB1: deferred until min wait time elapsed

// wwan0 net port is detected via udev, a set of port identification
// parameters are preloaded.
[34.779] [wwan0] port contents loaded:
[34.779] [wwan0]   bus: usb
[34.779] [wwan0]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0
[34.779] [wwan0]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.779] [wwan0]   driver: cdc_mbim
[34.780] [wwan0]   vendor: 1199
[34.780] [wwan0]   product: 9091
[34.780] [wwan0]   revision: 0006
[34.780] [base-manager] adding port wwan0 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0/net/wwan0
[34.782] [filter] (net/wwan0) port allowed: device is allowlisted by plugin (vid)
[34.783] [base-manager] additional port wwan0 in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// The support task is notified about the new wwan0 port, but still
// deferred.
[34.784] [plugin-manager] task 0: port grabbed: wwan0
[34.784] [plugin-manager] task 0,wwan0: new support task for port
[34.785] [plugin-manager] task 0,wwan0: deferred until min wait time elapsed

// cdc-wdm2 net port is detected via udev, a set of port
// identification parameters are preloaded.
[34.817] [cdc-wdm2] port contents loaded:
[34.817] [cdc-wdm2]   bus: usb
[34.817] [cdc-wdm2]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0
[34.817] [cdc-wdm2]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.817] [cdc-wdm2]   driver: cdc_mbim
[34.817] [cdc-wdm2]   vendor: 1199
[34.818] [cdc-wdm2]   product: 9091
[34.818] [cdc-wdm2]   revision: 0006
[34.818] [base-manager] adding port cdc-wdm2 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0/usbmisc/cdc-wdm2
[34.819] [filter] (usbmisc/cdc-wdm2) port allowed: device is allowlisted by plugin (vid)
[34.819] [base-manager] additional port cdc-wdm2 in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// The support task is notified about the new cdc-wdm2 port, but still
// deferred.
[34.820] [plugin-manager] task 0: port grabbed: cdc-wdm2
[34.820] [plugin-manager] task 0,cdc-wdm2: new support task for port
[34.820] [plugin-manager] task 0,cdc-wdm2: deferred until min wait time elapsed

// Once the “minimum wait time” elapses, the support task launches
// per-port checks to decide which plugin should manage the device.
[35.878] [plugin-manager] task 0: min wait time elapsed

// In this case, cdc-wdm2 is the first port that gets checked. The
// logic will go over all existing plugins to decide which ones can
// manage the port. Initially, the logs will include messages for all
// the plugins that cannot manage the port and why.
[35.885] [plugin/tp-link] port cdc-wdm2 filtered by implicit MBIM driver
[35.887] [plugin/simtech] port cdc-wdm2 filtered by implicit MBIM driver
[35.887] [plugin/via] port cdc-wdm2 filtered by subsystem
...
[35.896] [plugin/x22x] port cdc-wdm2 filtered by implicit MBIM driver
[35.896] [plugin/u-blox] port cdc-wdm2 filtered by subsystem

// Once all plugins have been checked, a list of possible plugins is
// built and each plugin is then asked to probe each port.
[35.899] [plugin-manager] task 0,cdc-wdm2: found '2' plugins to try
[35.900] [plugin-manager] task 0,cdc-wdm2: will try with plugin 'sierra'
[35.900] [plugin-manager] task 0,cdc-wdm2: will try with plugin 'generic'
[35.901] [plugin-manager] task 0,cdc-wdm2: started
[35.901] [plugin-manager] task 0,cdc-wdm2: checking with plugin 'sierra'

// The list of probe types required is decided per port type. For a
// MBIM device, only checking MBIM capabilities is enough.
[35.906] [plugin/sierra] probes required for port cdc-wdm2: 'mbim'
[35.908] [cdc-wdm2/probe] launching port probing: 'mbim'

// The next port to be checked is wwan0, again it goes through all the
// different available plugins.
[35.910] [plugin/tp-link] port wwan0 filtered by implicit MBIM driver
[35.910] [plugin/simtech] port wwan0 filtered by implicit MBIM driver

[35.915] [plugin/x22x] port wwan0 filtered by implicit MBIM driver
[35.915] [plugin/u-blox] port wwan0 filtered by implicit MBIM driver

// And the list of possible plugins is built for the wwan0 port.
[35.915] [plugin-manager] task 0,wwan0: found '2' plugins to try
[35.915] [plugin-manager] task 0,wwan0: will try with plugin 'sierra'
[35.915] [plugin-manager] task 0,wwan0: will try with plugin 'generic'
[35.915] [plugin-manager] task 0,wwan0: started
[35.915] [plugin-manager] task 0,wwan0: checking with plugin 'sierra'

// The probing of network ports does absolutely nothing, the operation
// will just be deferred until some other port suggests a plugin to be
// selected.
[35.917] [plugin/sierra] probing of port wwan0 deferred until result suggested

// The next port to be checked is ttyUSB1, again it goes through all
// the different available plugins.
[35.917] [plugin/tp-link] port ttyUSB1 filtered by implicit MBIM driver
[35.917] [plugin/simtech] port ttyUSB1 filtered by implicit MBIM driver

[35.921] [plugin/x22x] port ttyUSB1 filtered by implicit MBIM driver
[35.921] [plugin/u-blox] port ttyUSB1 filtered by implicit MBIM driver

// And the list of possible plugins is built for the ttyUSB1 port.
[35.922] [plugin-manager] task 0,ttyUSB1: found '2' plugins to try
[35.922] [plugin-manager] task 0,ttyUSB1: will try with plugin 'sierra'
[35.922] [plugin-manager] task 0,ttyUSB1: will try with plugin 'generic'
[35.922] [plugin-manager] task 0,ttyUSB1: started
[35.922] [plugin-manager] task 0,ttyUSB1: checking with plugin 'sierra'

// For the ttyUSB1 port we need to check different things that the
// plugin requires, it needs to know whether its AT or QCDM, and if
// it’s AT, whether it supports Intel specific XMM operations.
[35.925] [plugin/sierra] probes required for port ttyUSB1: 'at, at-xmm, qcdm'

// The port is known to be possibly AT because it’s flagged with a
// udev tag as a primary or secondary AT port, so all non-AT related
// probes are removed.
[35.925] [ttyUSB1/probe] no QCDM/QMI/MBIM probing in possible AT port
[35.926] [ttyUSB1/probe] port is not QCDM-capable
[35.926] [ttyUSB1/probe] port is not QMI-capable
[35.927] [ttyUSB1/probe] port is not MBIM-capable
[35.927] [ttyUSB1/probe] launching port probing: 'at, at-xmm'

// The next port to be checked is ttyUSB0, again it goes through all
// the different available plugins.
[35.928] [plugin/tp-link] port ttyUSB0 filtered by implicit MBIM driver
[35.928] [plugin/simtech] port ttyUSB0 filtered by implicit MBIM driver

[35.932] [plugin-manager] task 0,ttyUSB0: found '2' plugins to try
[35.932] [plugin-manager] task 0,ttyUSB0: will try with plugin 'sierra'
[35.933] [plugin-manager] task 0,ttyUSB0: will try with plugin 'generic'
[35.933] [plugin-manager] task 0,ttyUSB0: started
[35.933] [plugin-manager] task 0,ttyUSB0: checking with plugin 'sierra'

// As in the ttyUSB1 case, for ttyUSB0 the plugin also requires
// certain probes to be launched.
[35.933] [plugin/sierra] probes required for port ttyUSB0: 'at, at-xmm, qcdm'

// But ttyUSB0 is flagged in udev as being a GPS data port, so all
// probes end up removed, there is nothing to probe in such a port.
[35.934] [ttyUSB0/probe] GPS port detected
[35.934] [ttyUSB0/probe] port is not AT-capable
[35.935] [ttyUSB0/probe] port is not QCDM-capable
[35.935] [ttyUSB0/probe] port is not QMI-capable
[35.935] [ttyUSB0/probe] port is not MBIM-capable
[35.936] [ttyUSB0/probe] port probing finished: no more probings needed

// ttyUSB0 is the first port to finish all its probings, so the result
// of the suggested plugin is forwarded to all the other ports.
[35.938] [plugin-manager] task 0,wwan0: deferring support check until result suggested
[35.941] [plugin-manager] task 0,ttyUSB0: found best plugin for port (sierra)
[35.942] [plugin-manager] task 0,ttyUSB0: finished in '1.549135' seconds
[35.951] [plugin-manager] task 0,ttyUSB0: found best plugin: sierra
[35.954] [plugin-manager] task 0,cdc-wdm2: got suggested plugin (sierra)

// The suggested plugin helps complete the wwan0 port probe task that was
// deferred.
[35.954] [plugin-manager] task 0,wwan0: deferred task completed, got suggested plugin (sierra)
[35.955] [plugin-manager] task 0,ttyUSB1: got suggested plugin (sierra)
[35.957] [plugin-manager] task 0: still 3 running probes (3 active): cdc-wdm2, wwan0, ttyUSB1

// The MBIM probing task in cdc-wdm2 starts.
[35.961] [cdc-wdm2/probe] probing MBIM...

// The AT probing task ttyUSB1 starts. Note that the port type udev
// tag only provides a hint of the protocol that may be supported, the
// daemon still checks for explicit AT protocol support.
[36.036] [ttyUSB1/at] opening serial port...
[36.045] [ttyUSB1/at] setting up baudrate: 57600
[36.048] [ttyUSB1/at] no flow control explicitly requested for device
[36.051] [ttyUSB1/at] port attributes not fully set
[36.055] [ttyUSB1/at] device open count is 1 (open)
[36.058] [plugin-manager] task 0,wwan0: checking with plugin 'sierra'
[36.058] [plugin/sierra] probing of port wwan0 deferred until result suggested
[36.081] [plugin-manager] task 0,wwan0: completed, got suggested plugin (sierra)
[36.081] [plugin-manager] task 0,wwan0: finished in '1.297005' seconds
[36.082] [plugin-manager] task 0,wwan0: best plugin matches device reported one: sierra
[36.083] [plugin-manager] task 0: still 2 running probes (2 active): cdc-wdm2, ttyUSB1

// The MBIM port probing task finishes and reports whether the port is
// MBIM capable.
[36.260] [cdc-wdm2/probe] port is MBIM-capable
[36.262] [/dev/cdc-wdm2] closing device...
[36.286] [plugin-manager] task 0,cdc-wdm2: found best plugin for port (sierra)
[36.286] [plugin-manager] task 0,cdc-wdm2: finished in '1.465742' seconds
[36.286] [plugin-manager] task 0,cdc-wdm2: best plugin matches device reported one: sierra
[36.287] [plugin-manager] task 0: still 1 running probes (1 active): ttyUSB1
[36.321] [plugin-manager] task 0: extra probing time elapsed
[36.321] [plugin-manager] task 0: still 1 running probes (1 active): ttyUSB1
[36.878] [plugin-manager] task 0: min probing time elapsed
[36.879] [plugin-manager] task 0: still 1 running probes (1 active): ttyUSB1

// AT probing in this case completely fails in ttyUSB1, so it is
// flagged as not being AT capable.
[42.778] [ttyUSB1/at] --> 'AT<CR>'
[45.778] [ttyUSB1/at] --> 'AT<CR>'
[48.777] [ttyUSB1/at] --> 'AT<CR>'
[51.776] [ttyUSB1/at] --> 'AT<CR>'
[54.778] [ttyUSB1/probe] port is not AT-capable
[54.780] [plugin-manager] task 0,ttyUSB1: found best plugin for port (sierra)
[54.780] [plugin-manager] task 0,ttyUSB1: finished in '20.373198' seconds
[54.785] [plugin-manager] task 0,ttyUSB1: best plugin matches device reported one: sierra

// The whole device probing sequence takes around 20s in this case,
// mainly due to the AT command timeouts happening in ttyUSB1.
[54.785] [plugin-manager] task 0: no more ports to probe
[54.785] [plugin-manager] task 0: finished in '20.412880' seconds

// The plugin manager ends up creating a new modem object via the
// Sierra plugin.
[54.787] [device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1] creating modem with plugin 'sierra' and '4' ports
[54.791] [plugin/sierra] (sierra) MBIM-powered Sierra modem found...
[54.894] [cdc-wdm2/mbim] port monitoring enabled in MBIM port
[54.898] [modem0] port 'usbmisc/cdc-wdm2' grabbed
[54.901] [modem0] port 'net/wwan0' grabbed
[54.902] [plugin/sierra] could not grab port ttyUSB1: Cannot add port 'tty/ttyUSB1', unhandled port type
[54.905] [modem0] port 'tty/ttyUSB0' grabbed
[54.910] [modem0] net/wwan0: net (data)
[54.911] [modem0] tty/ttyUSB0: gps (nmea)
[54.912] [modem0] usbmisc/cdc-wdm2: mbim
[54.938] [base-manager] modem for device '/sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1' successfully created