This is the documentation site for ModemManager and its accompanying libraries (libmbim, libqmi and libqrtr-glib).
This the multi-page printable view of this section. Click here to print.
Welcome to ModemManager
- 1: libmbim
- 1.1: API reference
- 1.2: Dependencies
- 1.3: Building
- 1.3.1: Building libmbim 1.26 or later with Meson
- 1.3.2: Building libmbim 1.26 or earlier with GNU autotools
- 1.4: The MBIM protocol and the Microsoft extensions
- 2: libqrtr-glib
- 2.1: API reference
- 2.2: Dependencies
- 2.3: Building
- 3: libqmi
- 3.1: API reference
- 3.2: Dependencies
- 3.3: Building
- 4: ModemManager
- 4.1: Dependencies
- 4.2: Building
- 4.2.1: Building ModemManager 1.18 or later with Meson
- 4.2.2: Building ModemManager 1.18 or earlier using GNU autotools
- 4.3: Debugging
- 4.4: FCC unlock procedure
- 4.5: WWAN device types
- 4.6: Port and device detection
- 5: Contribution Guidelines
- 5.1: Using gitlab
- 5.1.1: Basic setup
- 5.1.2: Developer setup
- 5.2: Coding style
- 5.3: git commit style
- 5.4: Merge requests
- 5.5: Project communication
- 6: Frequently Asked Questions
1 - libmbim
This section provides information about the libmbim
library.
1.1 - API reference
The libmbim-glib
API reference provides a detailed list of operations that may be performed with MBIM devices.
Most of the documentation pages are automatically generated from the database of messages that the project maintains, and therefore it won’t give information about the purpose of the operations, or the exact format of the retrieved fields. The documentation is anyway extremely helpful when writing software using the library, as it provides a quick way to browse the interfaces and the expected fields in each message.
In order to know the exact purpose of each message or the format of the retrieved fields, please refer to the generic MBIM services references from the USB-IF or to the vendor-specific service references. Most of these documents are publicly available and don’t require any NDA.
Online references
The most up to date API reference of the libmbim-glib
library is kept in the following location:
The full list of API references published is kept for future reference:
- 1.28.0
- 1.26.0
- 1.24.0
- 1.22.0
- 1.20.0
- 1.18.0
- 1.16.0
- 1.14.0
- 1.12.0
- 1.10.2, 1.10.0
- 1.8.0
- 1.6.0
- 1.4.0
- 1.2.0
- 1.0.0
There is no API reference published for stable release updates that didn’t have any API change.
Local reference
The API reference is usually installed along with the libmbim-glib
library (sometimes as a separate distribution package) under /usr/share/gtk-doc/html/libmbim-glib/
and can be browsed locally via the Devhelp tool. The version of the installed reference will be the one applying to the libmbim-glib
library installed in the system.
1.2 - Dependencies
Common dependencies
Before you can compile the libmbim library, you will need at least the following tools:
- A compliant C toolchain: e.g.
glibc
ormusl libc
,gcc
orclang/llvm
. - pkg-config, a tool for tracking the compilation flags needed for libraries.
- The glib2 library.
- For libmbim >= 1.26, glib2 >= 2.56.
- For libmbim >= 1.24, glib2 >= 2.48.
- For libmbim >= 1.16 and < 1.24, glib2 >= 2.36
- For libmbim >= 1.0 and < 1.16, glib2 >= 2.32
In addition to the previous mandatory requirements, the project also has several optional dependencies that would be needed when enabling additional project features:
- gtk-doc tools, in order to regenerate the documentation.
- gobject-introspection, in order to generate the introspection support.
Dependencies when building libmbim 1.26 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 libmbim 1.26 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:
- GNU autotools (autoconf/automake/libtool).
- Autoconf archive, in the 1.22 and 1.24 series exclusively.
1.3 - Building
This section provides information about how to build and install the libmbim
library.
1.3.1 - Building libmbim 1.26 or later with Meson
The first stable series with support for building with the meson suite is 1.26. All the older stable series before 1.26 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/libmbim.git
$ cd libmbim
$ meson setup build --prefix=/usr
$ 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
. - 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 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 \
--libdir=/usr/lib/x86_64-linux-gnu \
--buildtype=release \
-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 libmbim 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.
1.3.2 - Building libmbim 1.26 or earlier with GNU autotools
The last stable series with support for building with the GNU autotools suite is 1.26. All the new stable series after 1.26 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/libmbim/libmbim-1.26.0.tar.xz
$ tar -Jxvf libmbim-1.26.0.tar.xz
$ cd libmbim-1.26.0
$ ./configure --prefix=/usr
$ 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 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 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 library 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 \
--libdir=/usr/lib/x86_64-linux-gnu \
--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 --depth 1 --branch 1.26.0 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git
$ cd libmbim
$ NOCONFIGURE=1 ./autogen.sh
$ ./configure --prefix=/usr
$ 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 libmbim 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 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.
1.4 - The MBIM protocol and the Microsoft extensions
The MBIM standard
The Mobile Broadband Interface Model (MBIM) is a standard created by the USB Implementers Forum for high-speed mobile broadband modem devices. This standard defines a new USB networking subclass for communication between the host system and the modem device, with two separate features:
- A MBIM USB device model that provides multiple IP connections over a single USB interface without the need for 802.3 frames (as was the case with NCM and other models for Ethernet over USB). Data transferred over this type of network interfaces are IP-only packets, without any additional link level header.
- A MBIM control protocol for communicating with modem devices. This protocol is exclusively used in the interface between the host and the modem. It has no direct mapping with the networking protocols used by the modem in the radio interface.
The “Universal Serial Bus Communications Class Subclass Specification for Mobile Broadband Interface Model - Version 1.0, Errata 1” (MBIM 1.0 from now on) was released on May 1st, 2013 and is the last official version of the original protocol specification. The definition of this protocol was a joint effort between different companies like Ericsson, Microsoft, Qualcomm, Nokia, and others.
The standard covered both 3GPP (GSM/UMTS/LTE) and 3GPP2 (CDMA/EVDO) devices, but effectively only the former ones have been integrated with MBIM support. There are currently no 3GPP2 devices with MBIM support available, as 3GPP2 technologies have been gradually phased out.
The standard was successful primarily because Microsoft used it as a reference implementation for WWAN management in their Windows operating system. Devices that support this specification would not need additional vendor-specific drivers to be properly integrated into the system’s network stack.
To take full advantage of 5G devices, which have data rates that are higher than what USB can support, modems now support connections to the PCI bus in addition to (or instead of) USB. The original USB device model is not used in PCI mode, but the MBIM control protocol can still be used to communicate with the device.
The MBIM control protocol
The protocol defines the communication between the host and the modem by providing:
- Different message types for different purposes.
- Different services grouping operations that are related to each other.
- Different request/responses and indications in each service.
The protocol assumes that there is a single control point in the host. This control point is responsible for managing the MBIM session by opening it explicitly when communication begins and closing it explicitly when communication is no longer expected. The host is not able to perform any operation on the device if there is no open MBIM session.
MBIM messages
Message types
The protocol defines different binary message types with different formats.
Some of them are used to establish the channel of communication with the modem:
- Open Message (Host->Modem): Initialization request.
- Open Done Message (Host<-Modem): Initialization response.
- Close Message (Host->Modem): Close request.
- Close Done Message (Host<-Modem): Close response.
Some of the messages are used to report errors in the protocol; which may be sent either from the host or from the modem:
- Host Error Message (Host->Modem): Host-reported error.
- Modem Error Message (Host<-Modem): Modem-reported error.
And finally, some messages provide access to the different operations defined in each service. All these message types have theoretical full message length of up to 2^32 bytes, and are split into separate transactions as appropriate.
- Command Message (Host->Modem): Request of a given command: either SET or GET.
- Command Done Message (Host<-Modem): Response to a given command.
- Indication Message (Host<-Modem): Unsolicited messages sent by the modem. Indication messages may be enabled or disabled by the host explicitly.
Message format
The format of the MBIM messages defined in the MBIM 1.0 protocol specification is fixed and strict, and has certain interesting properties that make it easier to process:
- The messages define a fixed amount of fields, which are always included.
- The messages are built with a fixed-sized block first containing the fixed-sized field contents (e.g. integers, uuid), followed by a variable-sized block containing the data of fields that don’t have a fixed size (e.g. strings, arrays).
- Integers are encoded either in 32bits (even for smaller types like booleans or 16-bit numbers), or in 64 bits, always in little endian.
- Variable-sized fields are defined first in the fixed-sized block via an “OL pair”. This is a pair of 32bit integers defining the byte offset inside the variable-sized block where the data of the field resides, and the length of the data in bytes.
- All data contents of fields in the variable-sized block are padded to 32bits.
- Arrays of elements (either integers, strings or structs) are supported. The array field is defined as an “OL pair”. The data of the array that is defined in the variable-sized block of the message may itself be split into its own fixed-sized and variable-sized blocks.
- All strings are encoded in UTF-16LE and limited to the code points inside the Basic Multilingual Plane, padded to 32bits when necessary.
- All fields aligned at 32bit boundaries!
The following image shows an example of a MBIM 1.0 Register State response message.
MBIM 1.0 services
The Basic Connect service
The Basic Connect service is the most useful service among the generic ones, as it provides all the basic capabilities the host requires to control the modem device. This service provides operations to query SIM status, unlock PIN, query and request network registration, manage data connectivity and many more.
The full list of operations defined in the MBIM protocol specification for this service is as follows (mandatory ones given in bold):
- MBIM_CID_DEVICE_CAPS: Device capabilities. This message allows querying for the capabilities of the modem, e.g. to know whether it is a 3GPP (GSM/UMTS/LTE) or a 3GPP2 (CDMA/EVDO) device.
- MBIM_CID_SUBSCRIBER_READY_STATUS: Subscriber ready status. This message allows querying for the details and state of the SIM card.
- MBIM_CID_RADIO_STATE: Radio state. This message allows controlling the power state of the radio interface.
- MBIM_CID_PIN: PIN. This message allows unlocking/enabling/disabling the PIN lock (e.g. SIM-PIN or SIM-PUK).
- MBIM_CID_PIN_LIST: PIN list. This message returns a list of all lock types supported by the modem and the status of each of them.
- MBIM_CID_HOME_PROVIDER: Home provider. This message provides information about the home provider as per the current SIM card in use.
- MBIM_CID_PREFERRED_PROVIDERS: Preferred providers. This command allows querying the list of preferred providers, e.g. to know which operator would be used when roaming in a different network.
- MBIM_CID_VISIBLE_PROVIDERS: Visible providers. This message allows requesting a network scan to look for service providers nearby.
- MBIM_CID_REGISTER_STATE: Register state. This command allows management of the network registration, e.g. to know the current registration state or to manually lock into a specific operator.
- MBIM_CID_PACKET_SERVICE: Packet service. This command allows management of the packet service domain state.
- MBIM_CID_SIGNAL_STATE: Signal state. This command allows querying and getting notified of the signal state information.
- MBIM_CID_CONNECT: Connect. This command allows activating a new packet data connection.
- MBIM_CID_PROVISIONED_CONTEXTS: Provisioned contexts. This command allows managing the list of profiles stored in the modem. Profiles are settings of different contexts/bearers that may be used to activate data connections.
- MBIM_CID_SERVICE_ACTIVATION: Service activation (e.g. in CDMA networks).
- MBIM_CID_IP_CONFIGURATION: IP configuration. This command allows querying the IP configuration the modem has agreed with the network once the connection has been established.
- MBIM_CID_DEVICE_SERVICES: Device services. This command allows querying which MBIM services are supported by the device.
- MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST: Device service subscribe list. This command allows managing the subscription for the different indications the modem may emit.
- MBIM_CID_PACKET_STATISTICS: Packet statistics. This command allows querying the packet statistics of the ongoing data connections.
- MBIM_CID_NETWORK_IDLE_HINT: Network idle hint. This command may be used either by host or modem to notify the peer that there is no network traffic expected, e.g. if the system is entering some idle state.
- MBIM_CID_EMERGENCY_MODE: Emergency mode, allows reporting whether emergency services are supported by the modem.
- MBIM_CID_IP_PACKET_FILTERS: IP packet filters. This command allows the host to manage a set of filters (applicable to the IP stream exclusively) to let the mode wake up the host upon receiving certain packets.
- MBIM_CID_MULTICARRIER_PROVIDERS: Multicarrier providers. This message allows managing devices that may initially be bound to a certain carrier and can be configured to work with a different one. E.g. in CDMA networks where SIM cards are not used and the device itself is the one bound to the carrier through service activation.
The SMS service
The SMS service provides operations to manage Short Messaging Service messages in the device. It allows reading, sending and deleting messages, and configuring certain aspects of the SMS management logic, like the SMSC address.
The full list of operations defined in the MBIM protocol specification for this service is as follows:
- MBIM_CID_SMS_CONFIGURATION: SMS configuration.
- MBIM_CID_SMS_READ: Read.
- MBIM_CID_SMS_SEND: Send.
- MBIM_CID_SMS_DELETE: Delete.
- MBIM_CID_SMS_MESSAGE_STORE_STATUS: Store message status.
One important missing feature in this service is that it completely hides the existence of multiple SMS storages (e.g. SIM vs device). The service also lacks the support to store SMS messages before sending them.
The USSD service
The USSD service allows performing standard Unstructured Supplementary Service Data operations to exchange requests and responses with the serving network (e.g. to request top-up of the prepaid card balance).
- MBIM_CID_USSD: USSD operation.
The Phonebook service
The Phonebook service allows managing user contact information. The MBIM standard is not designed to support voice call management, so the phonebook management service is exclusively thought to be used along with the SMS operations (e.g. to associate phone numbers in the short messages with contact entries in the phonebook).
- MBIM_CID_PHONEBOOK_CONFIGURATION: Configuration.
- MBIM_CID_PHONEBOOK_READ: Read.
- MBIM_CID_PHONEBOOK_DELETE: Delete.
- MBIM_CID_PHONEBOOK_WRITE: Write.
As with the SMS case, the service lacks the support to expose the existence of multiple phonebook storages (e.g. SIM vs device).
The STK service
The STK service allows performing SIM Application Tookit operations as defined in the GSM standard. This service allows SIM cards to run simple applications for value-added services (e.g. browsing the Internet or reading email). STK is equivalent to USAT (USIM Application Toolkit) in USIMs or CAT (Card Application Toolkit) in UICC cards.
- MBIM_CID_STK_PAC: PAC.
- MBIM_CID_STK_TERMINAL_RESPONSE: Terminal response.
- MBIM_CID_STK_ENVELOPE: Envelope.
STK applications were once very common on early GSM devices that used WAP to access the internet, but they are no longer used as much.
The AUTH service
The AUTH service allows sending authentication challenges to the device using either the EAP-AKA, EAP-AKA’ or EAP-SIM authentication procedures.
- MBIM_CID_AUTH_AKA: EAP Authentication and Key Agreement (used in 3GPP UMTS networks).
- MBIM_CID_AUTH_AKAP: EAP Authentication and Key Agreement prime (used in non-3GPP networks like WiMAX, CDMA or EV-DO).
- MBIM_CID_AUTH_SIM: EAP Subscriber Identity Module (used in 3GPP GSM networks).
These user operations are not necessary in standard 3GPP modems, as the modem itself performs mutual authentication between the SIM card and the network through the radio interface connection. However, they are useful in devices that are trying to register with a 3GPP network through non-3GPP access (e.g. WiFi).
The DSS service
Device Service Streams (DSS) allow transferring large amounts of non-IP traffic data from modem to host and vice versa via USB bulk-in and bulk-out pipes. This enables different types of services to provide a channel with high bandwidth without the limitation inherent in the MBIM control port.
- MBIM_CID_DSS_CONNECT: Connect.
E.g. Microsoft plans to use this DSS service for modem log collection.
E.g. Huawei patented GNSS data over DSS in MBIM back in 2013, which is probably why we’re still stuck with serial ports for that same purpose.
The Microsoft Extensions
A team of engineers from different companies, each of them very likely with different needs and approaches, wrote the original MBIM 1.0 specification. Unfortunately, the scope of the reference was limited to the technologies used at the time of writing, and the protocol itself (e.g. strict message formats) didn’t leave room for easy updates without breaking the API. To solve the problem, major users of the protocol ended up doing their own updates.
Microsoft has been the major lead of MBIM protocol updates, as it integrates seamlessly with their Windows operating system. The updates have happened in two different ways trying not to break API of already existing messages:
- New service additions with new messages and enumeration types for either different features or new functionality.
- Update of already existing services via a method of negotiating the version of the messages to use between host and device.
The following sections define MBIM messages originally defined by Microsoft in italics (e.g. MBIM_CID_MS_PROVISIONED_CONTEXT_V2), while keeping the name of the messages without italics for commands that were originally defined in the MBIM 1.0 specification, even if later updated by Microsoft (e.g. MBIM_CID_CONNECT).
Microsoft defined services
The Microsoft Basic Connect Extensions service
This service implements support for several new operations, including multi-executor/multi-SIM support (e.g. if the modem has separate controllable radio stacks and/or SIM cards), EPS initial bearer configuration/status querying (i.e. attach APN) and many more. All these features are considered essential for the correct configuration and management of the device.
Given that all these messages are implemented in a completely separate service, there is no collision with other equivalent messages defined in the MBIM 1.0 specification. In this case, the protocol user should choose which message to use: the generic one from MBIM 1.0 or the specific one from the extensions service.
- MBIM_CID_MS_PROVISIONED_CONTEXT_V2: Provisioned contexts. This is a message equivalent to the generic MBIM_CID_PROVISIONED_CONTEXTS but with additions to the profile contents, like roaming allowance, access type or profile source information. One extremely important change in this update is that the unique identifier of the different provisioned contexts is no longer a numeric context id, but instead the APN type. In the Microsoft extensions different contexts are configured for different purposes; so one context may be for Internet traffic, while another one is for SUPL server access. This allows modem-initiated applications to unequivocally know the expected PDU session settings to use depending on the application type, without intervention from the host. The APN type does not serve any purpose in the communication of the modem with the network, it’s purpose is bound to the host and the modem only.
- MBIM_CID_MS_NETWORK_BLACKLIST: Network denylist.
- MBIM_CID_MS_LTE_ATTACH_CONFIG: LTE attach configuration.
- MBIM_CID_MS_LTE_ATTACH_STATUS: LTE attach status information.
- MBIM_CID_MS_SYS_CAPS: System capabilities.
- MBIM_CID_MS_DEVICE_CAPS_V2: Device capabilities. This is a message equivalent to the generic MBIM_CID_DEVICE_CAPS but with additional information for the multi-executor support.
- MBIM_CID_MS_DEVICE_SLOT_MAPPINGS: Device slot mappings.
- MBIM_CID_MS_SLOT_INFO_STATUS: Slot info status.
- MBIM_CID_PCO: Protocol configuration operations (PCO).
- MBIM_CID_MS_DEVICE_RESET: Device reset.
- MBIM_CID_BASE_STATIONS_INFO: Base stations info.
- MBIM_CID_LOCATION_INFO_STATUS: Location info status.
- MBIM_CID_VERSION: Protocol version query and report.
- MBIM_CID_MODEM_LOGGING_CONFIG: Modem logging configuration. Still not fully defined (e.g. missing command id).
Other feature-specific services
In addition to the new basic operations implemented in the Basic Connect Extensions service, Microsoft also defined additional services for different new features, including for example:
- The Microsoft Firmware ID service.
- The Microsoft Host Shutdown service.
- The Microsoft SAR service.
- The Microsoft UICC low level access service.
- The Microsoft Voice extensions service (misleading name, the only supported command is to query network identity and time zone information).
This list is not exhaustive, additional services or messages may exist.
Versioned updates on already existing services
One thing that Microsoft probably realized was that the strictly fixed format of MBIM messages does not leave much room for incremental updates of their contents. As seen in the MBIM_CID_MS_DEVICE_CAPS_V2, the contents of the original MBIM_CID_DEVICE_CAPS message were updated just to add one single integer value at the end of the message.
The solution to avoid needing completely new messages when existing ones need to be updated was providing a versioned approach for all existing messages (both the ones defined in the MBIM 1.0 standard and the Microsoft extensions).
When the host system boots, the process managing the MBIM operations will open the MBIM session, perform generic device service and command support identification, and then send a MBIM_CID_VERSION command to the modem, specifying which are the MBIM version (MBIM release number) and MBIMEx version (the MBIM Extensions release number) the host supports. The modem may support newer or older releases, so knowing which is the one supported by the host, it decides the final agreed version and reports it back to the host. In order for this logic to work properly, the software running in the host must support new MBIMEx releases incrementally, without losing the support of older ones.
- The MBIM release number is 1.0 by default, and is not expected to change any time soon as there are no new official MBIM releases planned by the USB-IF.
- The MBIMEx release number goes from 2.0 to 4.0 (as of this writing). No modem will report MBIMEx v1.0 supported because the specific command used to negotiate the versioning is implemented only in devices supporting at least MBIMEx v2.0 (i.e. if the command is not supported, the host can assume it must not use any versioned MBIM command).
The following flow shows an example agreement between the host supporting MBIMEx v3.0 and the modem supporting MBIMEx v2.0. The version agreed will always be the lowest common denominator of both version numbers, i.e. MBIMEx v2.0 in this case.
MBIMEx v2.0: NSA support
The MBIMEx v2.0 update introduces support for modems capable of 5G NSA connectivity. It provides updates for already existing messages, which will be available once the negotiated MBIMEx version support is at least v2.0.
- MBIM_CID_REGISTER_STATE: Register state. This update of the original MBIM 1.0 command introduces an additional field to report the preferred data classes.
- MBIM_CID_PACKET_SERVICE: Packet service state. This update of the original MBIM 1.0 command introduces a new frequency range field that allows reporting whether the 5G service is sub-6GHz or mmWave.
- MBIM_CID_SIGNAL_STATE: Signal state. This update of the original MBIM 1.0 command introduces reporting RSRP and SNR per available technology.
- MBIM_CID_MS_DEVICE_CAPS_V2: Device capabilities. This is not a real new message defined, it only extends the list of possible data class values to include 5G.
MBIMEx v3.0: 5G SA phase 1 support
The MBIMEx v3.0 update introduces support for basic 5G SA specific features.
The following already existing messages are updated:
- MBIM_CID_MS_DEVICE_CAPS_V2: Device capabilities. This update deprecates certain data class values that were introduced in MBIMEx v2.0 and adds new ones, along with a new data subclass field to report 5G-specific configurations (e.g. which exact type of 5G NSA is being used, like EN-DC or NE-DC). The command also provides information about supported LTE and 5GNR bands and many other things.
- MBIM_CID_SUBSCRIBER_READY_STATUS: Subscriber ready status. This update of the original MBIM 1.0 command includes information about the SIM type (e.g. whether it’s a physical SIM or an eSIM) and whether the SIM is removable or not.
- MBIM_CID_PACKET_SERVICE: Packet service state. This update of the original MBIM 1.0 command uses the new data subclass type, and introduces a new Tracking Area Identity (TAI) field.
- MBIM_CID_CONNECT: Connect. This update of the original MBIM 1.0 command increases the amount of fields that may be provided in a connection attempt (e.g. access type preference, APN type). It also changes how certain other fields like strings are formatted.
- MBIM_CID_IP_PACKET_FILTERS: IP packet filters. This update of the original MBIM 1.0 command introduces a new Filter ID field.
- MBIM_CID_MS_BASE_STATIONS_INFO: Base stations info. This update adds support for reporting 5G NR cell measurements.
- MBIM_CID_MS_LTE_ATTACH_STATUS: LTE attach status information). This update includes support for reporting the specific error emitted by the network upon an attach failure.
The following new messages are introduced:
- MBIM_CID_MS_MODEM_CONFIG: Modem configuration status. This new message allows the modem to report the status of modem configuration loading performed once a new SIM is activated in the modem.
- MBIM_CID_MS_REGISTRATION_PARAMS: Registration parameters. This new message is somewhat equivalent to the attach configuration support available for LTE devices, but for the 5G registration procedure. It provides settings that should be used during registration to the network, and allows specifying e.g. which 5G network slices the modem should connect to.
- MBIM_CID_MS_WAKE_REASON: Wake reason query and report. This new message allows the host to query the modem for the reason why it was woken up.
MBIMEx v4.0: 5G SA phase 2 support
The MBIMEx v4.0 update introduces support for advanced 5G SA specific features. This phase aims to support end-to-end User Equipment Route Selection (URSP) handling and multiple concurrent eMBB network slices. All valid slice types (SST) are supported at the MBIM protocol level. Functional requirements for non-eMBB slices are not implied and are subject to additional host and device-level support and features.
The following already existing messages are updated:
- MBIM_CID_MS_DEVICE_CAPS_V2: Device capabilities. The format of the message is not modified, but the list of supported capabilities now also reports whether the device is able to use URSP rules while not registered in the 5G core network (e.g. if registered only in the 4G core network).
- MBIM_CID_MS_REGISTRATION_PARAMS: Registration parameters. The message supports a new optional field including the Operating System ID (OSID). The device may use the host’s OSID in the communication with the network.
- MBIM_CID_SUBSCRIBER_READY_STATUS: Subscriber ready status. This update of the original MBIM 1.0 command allows specifying the exact SIM slot ID where the action should be performed. This allows querying the information and state of the SIM card that is reachable in the slot that is considered inactive for network registration purposes.
- MBIM_CID_PACKET_SERVICE: Packet service. This update of the original MBIM 1.0 command adds support for a new optional field including the 3GPP release number currently implemented by the network.
- MBIM_CID_CONNECT: Connect. This update of the original MBIM 1.0 command includes a new activation state field, which allows the host to specify how the modem should use the URSP rules to activate the connection or match an already established one. It also includes support for defining the 5G slice id to use in the PDU session setup.
- MBIM_CID_RADIO_STATE: Radio state. The format of the original MBIM 1.0 command is not modified, but the description of its fields is updated. In particular, the specification now defines that the host-controlled power state of the modem must initially be always off, and the modem should never change that automatically by itself. This means that the modems would always boot with radio communications disabled (e.g. airplane mode) and only enable them once the host requests to do so.
- MBIM_CID_MS_PROVISIONED_CONTEXT_V2: Provisioned contexts v2. This message is updated to allow defining 5G slice ids to profiles stored in the modems.
The following new messages are introduced:
- MBIM_CID_MS_NETWORK_PARAMS: Network parameters. This new message allows the host to be notified of network-initiated configuration changes (e.g. allowed or rejected slices), for example when getting into a different tracking area.
- MBIM_CID_MS_UE_POLICY: UE policy. This new message allows the host to be notified of network-initiated UE policy changes (URSP rules as per 3GPP TS 24.526).
The MBIMEx v4.0 update also includes updates to other feature-specific services, such as the UICC low-level access service.
Message format in Microsoft Extensions
The format of the messages in the new Microsoft extensions is mostly similar to the one in the MBIM 1.0 specification, but they include certain features that make them more dynamic and extensible. However, not all the changes to the format have been made with care. In some instances, the changes introduced are unnecessary and add more complexity than anything else.
- MBIMEx v3.0 introduces Type-Length-Value (TLV) fields for both basic (e.g. strings) and complex data structures. Unlike other protocols like Qualcomm’s QMI, the values stored in the TLVs defined by Microsoft do not follow a common structure. Each TLV value content has its own specific format.
- TLV fields may be mandatory (i.e. explicitly defined in the contents of a given message) or optional (added in a new generic “Unnamed IEs” field at the end of the message.
- Certain messages will use LO (length+offset) pairs instead of OL (offset+length) pairs to define position and size of the data in the variable-sized buffer. This totally looks like an oversight in the protocol definition.
- Certain messages in the MBIM extensions define fixed-sized contents (e.g. structs with a fixed amount of fields with a known size) also in the variable-sized buffer, by providing an OL pair. This actually has a useful side effect, which is that the fields can be treated as optional (for example, if the OL pair specifies a 0-byte length).
- Certain messages will include strings encoded in UTF-8 instead of UTF-16LE.
- Integer types smaller than 32bits are introduced, e.g. 16bits.
- Certain messages introduce unreasonably complex types, e.g. an array of bytes where the length field represents the size of the original array, but which only up to 255 items are included in the array itself (i.e. size may be reported as 1024 but only 255 bytes given).
- The contents of the messages are not always guaranteed to be strictly aligned at 32bit boundaries any more.
Other services from manufacturers and operators
In addition to the extensions defined by Microsoft, other companies have also implemented their own MBIM services for different purposes. To name a few:
- AT&T defines the ATDS service that supports methods to query detailed signal quality information (e.g. RSRP, RSRQ) in LTE capable devices. This logic is now superseded by the Microsoft extensions, which are also capable of reporting 5GNR signal quality information.
- Intel defines a Firmware Update service with commands to request rebooting the module into firmware download mode.
- Qualcomm defines a QMI service that allows running any kind of QMI operation over MBIM transparently. All Qualcomm-based MBIM modems support this.
- Qualcomm also defines a QDU service that supports performing the whole device firmware upgrade operation (including file download to the module) via MBIM requests and responses.
2 - libqrtr-glib
This section provides information about the libqrtr-glib
library.
2.1 - API reference
The libqrtr-glib
API reference provides a detailed list of operations that may be performed with QRTR nodes.
Online references
The most up to date API reference of the libqrtr-glib
library is kept in the following location:
The full list of API references published is kept for future reference:
There is no API reference published for stable release updates that didn’t have any API change.
Local reference
The API reference is usually installed along with the libqrtr-glib
library (sometimes as a separate distribution package) under /usr/share/gtk-doc/html/libqrtr-glib/
and can be browsed locally via the Devhelp tool. The version of the installed reference will be the one applying to the libqrtr-glib
library installed in the system.
2.2 - Dependencies
Common dependencies
Before you can compile the libqrtr-glib library, you will need at least the following tools:
- A compliant C toolchain: e.g.
glibc
ormusl libc
,gcc
orclang/llvm
. - pkg-config, a tool for tracking the compilation flags needed for libraries.
- The glib2 library.
- For libqrtr-glib >= 1.2, glib2 >= 2.56.
- For libqrtr-glib >= 1.0, glib2 >= 2.48
In addition to the previous mandatory requirements, the project also has several optional dependencies that would be needed when enabling additional project features:
- gtk-doc tools, in order to regenerate the documentation.
- gobject-introspection, in order to generate the introspection support.
When building from a git checkout instead of from a source tarball, the following additional dependencies are required:
- GNU autotools (autoconf/automake/libtool).
- Autoconf archive
Dependencies when building libqrtr-glib 1.2 or later with meson
When building with meson, the following additional dependencies are required:
Dependencies when building libqrtr-glib 1.0 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:
- GNU autotools (autoconf/automake/libtool).
- Autoconf archive.
2.3 - Building
This section provides information about how to build and install the libqrtr-glib
library.
2.3.1 - Building libqrtr-glib 1.2 or later with Meson
The first stable series with support for building with the meson suite is 1.2. All the older stable series before 1.2 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 --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libqrtr-glib.git
$ cd libqrtr-glib
$ meson setup build --prefix=/usr
$ 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
. - 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 is enabled by default. In order to disable it, the additional
-Dintrospection=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 \
--libdir=/usr/lib/x86_64-linux-gnu \
--buildtype=release \
-Dgtk_doc=true \
-Dintrospection=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 libqrtr-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.3.2 - Building libqrtr-glib 1.0 using GNU autotools
The last stable series with support for building with the GNU autotools suite is 1.0. All the new stable series after 1.0 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/libqrtr-glib/libqrtr-glib-1.0.0.tar.xz
$ tar -Jxvf libqrtr-glib-1.0.0.tar.xz
$ cd libqrtr-glib-1.0.0
$ ./configure --prefix=/usr
$ 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 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 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 library 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 \
--libdir=/usr/lib/x86_64-linux-gnu \
--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/libqrtr-glib.git
$ cd libqrtr-glib
$ NOCONFIGURE=1 ./autogen.sh
$ ./configure --prefix=/usr
$ 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 libqrtr-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 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 - libqmi
This section provides information about the libqmi
library.
3.1 - API reference
The libqmi-glib
API reference provides a detailed list of operations that may be performed with QMI devices.
Most of the documentation pages are automatically generated from the database of messages that the project maintains, and therefore it won’t give information about the purpose of the operations, or the exact format of the retrieved fields. The documentation is anyway extremely helpful when writing software using the library, as it provides a quick way to browse the interfaces and the expected fields in each message.
In order to know the exact purpose of each message or the format of the retrieved fields, please refer to the generic QMI services references from Qualcomm or to the vendor-specific service references. Most of these documents are only provided by Qualcomm under NDAs.
Online references
The most up to date API reference of the libqmi-glib
library is kept in the following location:
The full list of API references published is kept for future reference:
- 1.32.0
- 1.30.8, 1.30.2, 1.30.0
- 1.28.6, 1.28.0
- 1.26.6, 1.26.2, 1.26.0
- 1.24.10, 1.24.6, 1.24.0
- 1.22.0
- 1.20.0
- 1.18.0
- 1.16.0
- 1.14.2, 1.14.0
- 1.12.0
- 1.10.6, 1.10.4, 1.10.2, 1.10.0
- 1.8.0
- 1.6.0
- 1.4.0
There is no API reference published for stable release updates that didn’t have any API change.
Local reference
The API reference is usually installed along with the libqmi-glib
library (sometimes as a separate distribution package) under /usr/share/gtk-doc/html/libqmi-glib/
and can be browsed locally via the Devhelp tool. The version of the installed reference will be the one applying to the libqmi-glib
library installed in the system.
3.2 - Dependencies
Common dependencies
Before you can compile the libqmi library, you will need at least the following tools:
- A compliant C toolchain: e.g.
glibc
ormusl libc
,gcc
orclang/llvm
. - pkg-config, a tool for tracking the compilation flags needed for libraries.
- The glib2 library.
- For libqmi >= 1.30, glib2 >= 2.56.
- For libqmi >= 1.26, glib2 >= 2.48.
- For libqmi >= 1.18 and < 1.26, glib2 >= 2.36
- For libqmi >= 1.0 and < 1.18, glib2 >= 2.32
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 QMI-over-MBIM feature.
- For libqmi >= 1.22, libmbim >= 1.18.
- For libqmi >= 1.16 and < 1.22, libmbim >= 1.14.
- libqrtr-glib, in order to use the QMI-over-QRTR feature.
- For libqmi >= 1.28, libqrtr-glib >= 1.0.
- The libgudev library, in order to extend the
qmi-firmware-update
options and behavior.- For libqmi >= 1.30, libgudev >= 232.
- For libqmi >= 1.18, libgudev >= 147.
- gtk-doc tools, in order to regenerate the documentation.
- gobject-introspection, in order to generate the introspection support.
Dependencies when building libqmi 1.30 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 libmbim 1.30 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:
- GNU autotools (autoconf/automake/libtool).
- Autoconf archive, in the 1.26 and 1.28 series exclusively.
3.3 - Building
This section provides information about how to build and install the libqmi
library.
3.3.1 - Building libqmi 1.30 or later with Meson
The first stable series with support for building with the meson suite is 1.30. All the older stable series before 1.30 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/libqmi.git
$ cd libqmi
$ meson setup build --prefix=/usr
$ 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
. - The QMI-over-MBIM feature is enabled by default. In order to disable it, the additional
-Dmbim_qmux=false
switch should be given. - The QMI-over-QRTR feature is enabled by default. In order to disable it, the additional
-Dqrtr=false
switch should be given. - If the project should build support for only a certain subset of QMI commands, the user can select which collection of commands should be used with the
-Dcollection
switch:-Dcollection=minimal
will select the minimum number of QMI commands required to have a data connection up.-Dcollection=basic
will select the minimum number of QMI commands required by ModemManager.-Dcollection=full
, or omitting the switch, will select all the available QMI commands.-Dcollection=XXXX
will select the QMI commands listed in the user-provideddata/qmi-collection-XXXX.json
file in the project sources.
- 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 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 \
--libdir=/usr/lib/x86_64-linux-gnu \
--buildtype=release \
-Dcollection=basic \
-Dmbim_qmux=false \
-Dqrtr=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 libqmi 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.
3.3.2 - Building libqmi 1.30 or earlier using GNU autotools
The last stable series with support for building with the GNU autotools suite is 1.30. All the new stable series after 1.30 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/libqmi/libqmi-1.30.0.tar.xz
$ tar -Jxvf libqmi-1.30.0.tar.xz
$ cd libqmi-1.30.0
$ ./configure --prefix=/usr
$ 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 QMI-over-MBIM feature is required, the additional
--enable-mbim-qmux
should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies. - If the QMI-over-QRTR feature is required, the additional
--enable-qrtr
should be given. Omitting this switch will imply auto-detecting whether the feature can be built with the already installed dependencies. - If the project should build support for only a certain subset of QMI commands, the user can select which collection of commands should be used with the
--enable-collection
switch:--enable-collection=minimal
will select the minimum number of QMI commands required to have a data connection up.--enable-collection=basic
will select the minimum number of QMI commands required by ModemManager.--enable-collection=full
, or omitting the switch, will select all the available QMI commands.--enable-collection=XXXX
will select the QMI commands listed in the user-provideddata/qmi-collection-XXXX.json
file in the project sources.
- 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 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 library 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 \
--libdir=/usr/lib/x86_64-linux-gnu \
--enable-mbim-qmux \
--enable-qrtr \
--enable-collection=basic \
--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/libqmi.git
$ cd libqmi
$ NOCONFIGURE=1 ./autogen.sh
$ ./configure --prefix=/usr
$ 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 libqmi 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 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.
4 - ModemManager
This section provides information about the ModemManager
daemon, the libmm-glib
library, and the mmcli
command line tool.
4.1 - Dependencies
Common dependencies
Before you can compile the ModemManager project, you will need at least the following tools:
- A compliant C toolchain: e.g.
glibc
ormusl libc
,gcc
orclang/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:
- GNU autotools (autoconf/automake/libtool).
- Autoconf archive, in the 1.16 series exclusively.
4.2 - Building
This section provides information about how to build and install the ModemManager
daemon and its libraries and utilities.
4.2.1 - Building ModemManager 1.18 or later with Meson
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.
4.2.2 - Building ModemManager 1.18 or earlier 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.
4.3 - Debugging
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.4 - FCC unlock procedure
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 anERROR
response.QMI DMS Set Operating Mode (ONLINE)
will fail, likely with anInvalid transition
error.MBIM Radio State (ON)
will fail, likely with anOperation 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.
4.5 - WWAN device types
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.
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).
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
…).
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.
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.
4.6 - Port and device detection
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 thecdc-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 originalcdc-wdm
ports in theusbmisc
subsystem, but these are considered duplicates and ignored byModemManager
.qrtr
subsystem: This is not a real device subsystem in the kernel, butModemManager
uses this to reference modem management nodes exposed in the Qualcomm specific QRTR bus. Given that these nodes don’t have any exposure insysfs
, there is no way to bindudev
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).
- ID_MM_PORT_TYPE_AT_PRIMARY
- ID_MM_PORT_TYPE_AT_SECONDARY
- ID_MM_PORT_TYPE_AT_GPS_CONTROL
- ID_MM_PORT_TYPE_AT_PPP
- ID_MM_PORT_TYPE_QCDM
- ID_MM_PORT_TYPE_GPS
- ID_MM_PORT_TYPE_AUDIO
- ID_MM_PORT_TYPE_QMI
- ID_MM_PORT_TYPE_MBIM
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-
or79-mm-
. This is so that the user-defined rules are processed after the generic rules (which are all installed as77-mm-
) and before the candidate rules (in the80-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 customudev
rule parser used inopenwrt
. - Following the same pattern as the
ModemManager
udev
rules, the rules should be run onadd
,change
,move
andbind
ACTION
s. - 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
vsSUBSYSTEM
, orATTRS
vsATTR
and so on. One (without the trailingS
) matches a specific device in the device hierarchy, while the other (with the trailingS
) matches a device and all its parents on the hierarchy. For example, a TTY port in a USB device will definitely matchSUBSYSTEMS==”usb”
(because a direct parent of the TTY port will be the physical USB device) but it will also matchSUBSYSTEMS==”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 ofudev
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 theID_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 inttyACM
ports, looking at which kernel drivers are in use, or even based on port type hint rules already defined inModemManager
. 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. withID_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.
- The old behavior, where ports were probed unless explicitly flagged with a specific
- 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
5 - Contribution Guidelines
This section provides information about how users can contribute to the project, either by reporting issues, suggesting new features or developing fixes.
5.1 - Using gitlab
The Mobile Broadband group in the gitlab instance maintained by the freedesktop.org community contains the following projects:
- ModemManager: https://gitlab.freedesktop.org/mobile-broadband/ModemManager
- libqmi: https://gitlab.freedesktop.org/mobile-broadband/libqmi
- libmbim: https://gitlab.freedesktop.org/mobile-broadband/libmbim
- libqrtr-glib: https://gitlab.freedesktop.org/mobile-broadband/libqrtr-glib
The following sections provide a quick overview of what the basic functionality is and how to set it up by users or first-time developers. This Community Edition gitlab instance is no different to others, so users that have used gitlab in the past should see no problem in using this site. For detailed help on all the features supported, the gitlab instance also publishes its own help.
5.1.1 - Basic setup
Cloning the upstream repository
If the user only wants to build and install the latest development versions (without suggesting any changes to them), the upstream source repositories can be checked out using git
and the HTTPS paths for each of them. These paths are given in the dialog displayed after clicking the Clone button.
The git clone commands for each of these repositories would be:
$ git clone https://gitlab.freedesktop.org/mobile-broadband/libqrtr-glib
$ git clone https://gitlab.freedesktop.org/mobile-broadband/libmbim.git
$ git clone https://gitlab.freedesktop.org/mobile-broadband/libqmi.git
$ git clone https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git
Creating a new user account
In order to access the basic functionality of the gitlab instance, like reporting new issues or commenting on already existing ones, a new user account should be registered in the gitlab instance.
Reporting new issues
The user can browse existing issues or report new ones in the project specific Issues page:
- ModemManager: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues
- libqmi: https://gitlab.freedesktop.org/mobile-broadband/libqmi/-/issues
- libmbim: https://gitlab.freedesktop.org/mobile-broadband/libmbim/-/issues
- libqrtr-glib: https://gitlab.freedesktop.org/mobile-broadband/libqrtr-glib/-/issues
Once the issue is reported, the maintainers may request to add additional explanations, or provide debug logs with detailed protocol information.
5.1.2 - Developer setup
Adding SSH keys to the user account
If the user is prepared to suggest changes to the upstream repositories, the first step is to setup at least one SSH key. You can create a public/private key pair locally in your PC as follows:
$ ssh-keygen -t rsa
The previous command will generate a public key (~/.ssh/id_rsa.pub
) and a private key (~/.ssh/id_rsa
). The user should then navigate in the gitlab site to the “SSH keys” section in the “User Settings” of the new user profile in order to register the SSH key. The user should copy and paste the public key that was generated (i.e. ~/.ssh/id_rsa.pub
).
Fork and checkout the project
Once the user is logged in the new account, a new Fork button will be shown at the top-right corner in each of the upstream project pages.
The user should only fork the project that needs to modify. There is really no need to create user forks if the user isn’t going to suggest any modification to the upstream repositories. E.g. if the user is planning to fix a bug in ModemManager, there would be no need to fork libmbim, libqmi or libqrtr-glib.
Once the project is forked, gitlab will create a whole new project page under the user account. E.g. if all four projects are forked by username
:
- ModemManager: https://gitlab.freedesktop.org/username/ModemManager
- libqmi: https://gitlab.freedesktop.org/username/libqmi
- libmbim: https://gitlab.freedesktop.org/username/libmbim
- libqrtr-glib: https://gitlab.freedesktop.org/username/libqrtr-glib
These forked projects will have their own Clone buttons, and when they are clicked, the user-specific clone paths will be shown.
The user should use the paths listed under Clone with SSH, and the clone operations will succeed if the SSH keys were configured properly in an earlier step.
$ git clone git@gitlab.freedesktop.org:username/libqrtr-glib.git
$ git clone git@gitlab.freedesktop.org:username/libmbim.git
$ git clone git@gitlab.freedesktop.org:username/libqmi.git
$ git clone git@gitlab.freedesktop.org:username/ModemManager.git
Setup upstream remote
As soon as the new user-specific git repositories are cloned, they will have the origin
remote configured to point to them. These git repositories will not be automatically kept in sync with the original upstream repositories, it is up to the user to do that.
In order to make sure the user can sync with the upstream repositories periodically, a new additional remote can be setup as follows:
$ cd libqrtr-glib
$ git remote add upstream https://gitlab.freedesktop.org/mobile-broadband/libqrtr-glib
$ cd libmbim
$ git remote add upstream https://gitlab.freedesktop.org/mobile-broadband/libmbim.git
$ cd libqmi
$ git remote add upstream https://gitlab.freedesktop.org/mobile-broadband/libqmi.git
$ cd ModemManager
$ git remote add upstream https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git
Once the upstream
remotes are setup, the user can now sync the main
branch between both. E.g.:
$ cd libqrtr-glib
$ git checkout main // change to the main branch
$ git fetch upstream // fetch updates from upstream remote
$ git merge upstream/main // merge changes from upstream main branch
$ git push origin main // update main branch in origin remote
$ cd libmbim
$ git checkout main
$ git fetch upstream
$ git merge upstream/main
$ git push origin main
$ cd libqmi
$ git checkout main
$ git fetch upstream
$ git merge upstream/main
$ git push origin main
$ cd ModemManager
$ git checkout main
$ git fetch upstream
$ git merge upstream/main
$ git push origin main
During development, it’s suggested to keep separate per-feature or per-fix branches, and keep the main
branch always in sync with the upstream repository.
5.2 - Coding style
Quoting the C coding style guidelines from the GNOME project:
The Single Most Important Rule when writing code is this: check the surrounding code and try to imitate it. As a maintainer it is dismaying to receive a patch that is obviously in a different coding style to the surrounding code. This is disrespectful, like someone tromping into a spotlessly-clean house with muddy shoes. So, whatever this document recommends, if there is already written code and you are patching it, keep its current style consistent even if it is not your favorite style.
So, the best way to learn and get used to the coding style used in this projects is really to read the already existing code, as that will help solve most of the doubts one may have when writing new code. If reading the code is not enough, the following coding style guidelines should help as well.
Basic formatting
Line length
There is no strict requirement on the length of the source code lines, especially since there are very long type and function names in e.g. libqmi or libmbim. It is up to the developer how to split lines if appropriate.
Comments
Code comments are always written between /*
and */
, and multiline comments will have a *
prefix in all lines except for the first one.
{
/* a very long multiline comment to explain something
* with a lot of detail; see how all the lines after the
* first one have the asterisk prefix.
*/
/* single line comments also in the same way, never with // */
}
Always place a whitespace after `/*` and before `*/`.
Indentation and alignment
The sources use 4 spaces to indent, there should be no tabs or longer indentations. In the same way, the alignment is exclusively done with spaces, never with tabs.
{
/* indented 4 spaces */
if (something) {
/* indented 4 more spaces */
do_something (variable1,
variable2,
variable3,
variable4);
/* aligned --^-- here */
}
}
Spacing
Both method calls and conditionals (e.g. if
, for
, while
…) should always have a whitespace before the (
character.
{
/* v-------- whitespace before ( */
if (something) {
/* v-------- whitespace before ( */
do_something (variable1,
variable2,
variable3,
variable4);
}
}
There should be no whitespace after (
or before )
.
Braces
Each function has its opening brace at the next line on the same indentation level as its header.
The blocks inside a function, however, have their opening braces at the same line as their respective control statements; closing braces remain in a line of their own, unless followed by a keyword else
or while
.
If the contents of the statement are one single command, the braces may be optionally skipped.
static void
a_nice_function (void)
{ /* <--------- open brace of function in next line */
if (something) { /* <--------- open brace of statement in same line */
...
do_something ();
} else if (something_else) { /* <--------- closing brace followed by else-if */
...
do_something_else ();
} else /* <--------- braces skipped for one-command contents */
do_something_completely_different ();
}
Variables
Variables are always named in lowercase, and separating words with underscores.
The name of the variable should clearly define the purpose of the variable. Using generic names are only allowed for certain very specific cases, e.g. a short name like i
is allowed for loop iterators and such.
Variables are defined always at the beginning of the code block where they’re scoped. If a variable is scoped inside an inner scope, it’s also better to define it inside the inner block itself.
If possible, the names of the variables given in the same block should also be vertically aligned. Depending on the length of the type names in the same variable block, more than one vertically aligned groups may be given.
After the definition of all variables, there should be a whiteline before the first method call.
{
/* all variables defined together at the beginning of the block */
GError *inner_error = NULL;
gint i;
/* <---- whiteline here! */
for (i = 0; i < SOME_MAX; i++) {
/* inside an inner block, variables that apply to the block;
* in this case with some variable types that are very long
* so they're aligned vertically in different groups */
SomeVeryLongTypeNameWeFindHere input_message;
AnotherDifferentVeryLongTypeNameWeGot output_message;
const gchar *name;
gint weight;
/* <---- whiteline here! */
...
name = do_something (i);
if (name)
break;
}
}
Pointers
When defining variables that are pointers, the asterisk must always go next to the variable name, never next to the type.
This is so that there is no confusion on what types are being declared if e.g. more than one variable is defined in the same line.
{
/* These are two pointers to guint variables. With the asterisk next to the
* variable name, it's clear they are both pointers. */
guint *val1, *val2;
/* If the asterisk was placed next to the type, it would get confusing.
* This is a pointer to a guint (val3) and a guint (val4), not two
* pointers. */
guint* val3, val4;
...
}
Methods
Methods are always named in lowercase, and separating words with underscores.
The name of the method should clearly define the purpose of the method.
If possible, the names of the method arguments given in the method declaration and definitions should also be vertically aligned. Depending on the length of the type names, more than one vertically aligned groups may be given.
When a method is defined, it should provide the return type of the method in a separate line, before the name of the method. When a method is declared, the return type should be given in the same line as the name of the method.
Definition of module private methods
Methods that are going to be used exclusively in the same source file where they are defined (private methods) should be made static
, and not declared in any header. The name of this kind of methods doesn’t need to have any explicit prefix.
/* return type and method name in separate lines */
static gboolean
do_something (gint max,
gint min,
const gchar *text,
GError **error)
{
/* definition here */
}
Declaration and definition of module public methods
Methods that are meant to be used out of the source file where they are defined (public methods) should have a clear declaration in a header file and the definition inside the source file with the same file name. All the public methods in the same module should have the same string prefix, clearly stating the module they come from.
E.g. in the header file some-module.h
:
/* return type and method name in the same line */
gboolean some_module_do_something (const gchar *text,
GError **error);
And in source file some-module.c
:
/* return type and method name in separate lines */
gboolean
some_module_do_something (const gchar *text,
GError **error)
{
/* definition here */
}
Symbols
Symbols are always named in uppercase, and separating words with underscores.
The name of the symbol should clearly define the purpose of the symbol.
Symbols are usually defined at the beginning of the header or source file, with an explanation of what they are for given in a comment.
In the same way as methods, if the symbols are defined in the header file of a module, the name of the symbol should have the common prefix used in the module.
/* Maximum time to wait for the operation to complete, in seconds */
#define SOME_MODULE_MAX_TIMEOUT_SECS 10
5.3 - git commit style
Having a proper style in the git commits suggested for inclusion in the projects is also a very important thing. This section provides some hints of what is expected from the git commits suggested by contributors.
As with the source code coding style, the best way to see what kind of git commit format is expected is to look at other commits from other developers in the same project.
Authorship
The author of the git commit should preferably a real person name (Firstname Lastname), as the author of the email is implicitly the one who holds the copyright of the changes done in the commit, unless explicitly stated e.g. with additional copyright lines in the source code.
Basic message formatting
The message of a git commit must be composed of:
- An initial first line with a short description of the change, prefixed by a “module: " string. The module could be some specific object in the code, or some protocol, or some other similar thing. If unsure, the best thing to get a feeling of what you should use as module would be to run
git log <FILE>
(beingthe main file being modified in the commit) and read what other developers have used as module when modifying that same file. - Then an empty whiteline.
- Then the body of the commit, including an optional longer description. This would be optional only for trivial changes for which the first description line is enough. For any change that is a bit more complex, the longer description can be considered mandatory. The body of the message may be composed by multiple paragraphs, and may also include additional information like real program logs, crash backtraces reported by gdb, or even valgrind memcheck log snippets (e.g. when fixing memory leaks).
For text content in the commit message (either first line or body) it is suggested to keep the maximum line length at 70 characteres maximum. This is not a strict rule for the first line though, sometimes just a few more characters are needed, and that would be acceptable.
For log snippets or backtraces included in the commit message, it is suggested to indent them a few characters. Also, there is no line length limitation in this case, but it is suggested to pretty-format them so that the information included is all valuable. E.g. when inserting program logs in the commit message, the developer may first clean them up to remove unrelated log lines, or even remove information that isn’t necessary (e.g. maybe the timestamps are irrelevant for the purpose of the included information, so they can be removed).
Commits may have a Signed-off-by:
line (e.g. as per git commit -s
) but this is not strictly necessary.
When fixing issues reported in the project gitlab, a Fixes <Bug URL>
line is suggested. When this commit is merged to the project git main, gitlab will automatically close the referred issue.
Examples
This is a properly formatted commit message:
base-modem: plug leaks when organizing ports
The GLists maintained in the logic need to be explicitly freed (just
the lists, not the list contents) if we exit early on error or if we
end up deciding that the specific ports are available but unsupported
by the plugin (e.g. if a plugin that doesn't support net ports finds
net ports in the modem).
==225333== 24 bytes in 1 blocks are definitely lost in loss record 2,024 of 5,525
==225333== at 0x483E77F: malloc (vg_replace_malloc.c:307)
==225333== by 0x506C539: g_malloc (in /usr/lib/libglib-2.0.so.0.6600.7)
==225333== by 0x508DC8F: g_slice_alloc (in /usr/lib/libglib-2.0.so.0.6600.7)
==225333== by 0x50636B4: g_list_append (in /usr/lib/libglib-2.0.so.0.6600.7)
==225333== by 0x17E671: mm_base_modem_organize_ports (mm-base-modem.c:1298)
==225333== by 0x1E4409: mm_plugin_create_modem (mm-plugin.c:1094)
==225333== by 0x162C81: mm_device_create_modem (mm-device.c:481)
==225333== by 0x15DE60: device_support_check_ready (mm-base-manager.c:218)
==225333== by 0x4EA8173: ??? (in /usr/lib/libgio-2.0.so.0.6600.7)
==225333== by 0x4EAC6E8: ??? (in /usr/lib/libgio-2.0.so.0.6600.7)
==225333== by 0x16730F: device_context_run_ready (mm-plugin-manager.c:1533)
==225333== by 0x4EA8173: ??? (in /usr/lib/libgio-2.0.so.0.6600.7)
These are NOT a properly formatted commit messages:
Update src/mm-broadband-modem.c, update src/mm-broadband-modem.h, update src/mm-modem-helpers.c, update src/mm-modem-helpers.h, update src/mm-base-modem.h .......
(lacks description of what the commit is doing)
Added dual sim support to Quectel plugin
(no module:
prefix; e.g. should have been quectel: added dual sim support
)
mm-broadband-modem: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut turpis turpis, euismod at gravida at, tincidunt at metus. Maecenas placerat laoreet arcu non luctus. Duis sit amet augue ullamcorper, tincidunt magna ac, porttitor metus.
(first line more than 70 chars)
Contents of the commit
The maintainers of the project will review the commits one by one and therefore, each commit should be self-contained:
- A single commit must only provide one single logical change. It is acceptable to include in the commit additional minor coding style modifications affecting the code being fixed, but that’s it.
- If the changes being suggested in a merge request are a lot, it is therefore expected to have a series of commits implementing the changes. Merge requests that contain one single commit with 5000 line changes across the project will be rejected right away.
- Commits fixing only coding style are also accepted. This is probably an exception to most free/open source software projects, so don’t assume this to be the default elsewhere.
The changes done in a single commit must NEVER break the build, because otherwise git bisect-ing would not be possible.
5.4 - Merge requests
Create a new local branch for the fix or feature
Once a local checkout of the project is available, the user can now create a new local branch for the new feature being developed or for the fix that is going to be suggested. The new branch should be based always on top of upstream/main
.
$ cd ModemManager
$ git fetch upstream
$ git checkout -b my-branch upstream/main
At this point, the user can start modifying files and using git to keep track of the changes, as usual.
Prepare and cleanup the branch
Once the user has developed a series of commits for a given fix or new feature, it is time to suggest the changes for review.
The first thing to do is to make sure the new branch is rebased on top of the latest upstream/main
. E.g. if the branch where the fix was developed was created 2 months ago, it is very likely that new changes have gone to the main
branch in the upstream repository; the user should make sure all those changes don’t conflict with the new ones being suggested.
$ cd ModemManager
$ git fetch upstream
$ git checkout my-branch
$ git rebase upstream/main
If the rebase cannot finish automatically, the user will need to perform an interactive rebase in order to fix any conflict that may have arised.
$ git rebase -i upstream/main
Checklist before pushing the branch for review
Key requirements
- Make sure the gitlab pipelines pass for your branch.
- Make sure git commit style is according to the expected format.
- Make sure coding style is according to the expected format.
The branch must allow git bisecting
In order to allow git bisecting the branch, no single commit should break the build at any point. This can be checked by running a build after each commit in the following way:
$ git rebase -i upstream/main --exec "make -j8"
No new gtk-doc warnings
The developer should make sure the local builds are done with --enable-gtk-doc
, and if there are new warnings introduced by the branch, these must be fixed before suggesting it for review.
E.g. adding a new MBIM service in libmbim could end up triggering the following warnings in the gtk-doc step:
DOC Scanning header files
DOC Introspecting gobjects
DOC Building XML
./libmbim-glib-unused.txt:1: warning: 21 unused declarations. They should be added to libmbim-glib-sections.txt in the appropriate place.
DOC Building HTML
DOC Fixing cross-references
html/libmbim-glib-QDU.html:287: warning: no link for: "MbimQduFileType" -> (<span class="type">MbimQduFileType</span>).
Learning how to fix these type of issues is easy, just investigate how other similar methods or types are documented, and do the same.
Push the branch and create a merge request
In order to create a new merge request against the upstream repository, the user should push the branch to the user-specific repository (origin
remote).
$ cd ModemManager
$ git checkout my-branch
$ git push origin my-branch
Enumerating objects: 57, done.
Counting objects: 100% (57/57), done.
Delta compression using up to 4 threads
Compressing objects: 100% (26/26), done.
Writing objects: 100% (47/47), 8.76 KiB | 2.92 MiB/s, done.
Total 47 (delta 35), reused 32 (delta 21), pack-reused 0
remote:
remote: To create a merge request for my-branch, visit:
remote: https://gitlab.freedesktop.org/username/ModemManager/-/merge_requests/new?merge_request%5Bsource_branch%5D=my-branch
remote:
To gitlab.freedesktop.org:username/ModemManager.git
* [new branch] my-branch -> my-branch
Once the branch is pushed, the git server will provide a link to create a merge request for the newly pushed branch, as seen above.
The user should open the given link, and gitlab will provide a short form to fill before the merge request is finished. Very important things to consider when filling in the form:
- If the merge request contains a series of commits, the user should write a description that explains the purpose of the whole series.
- If the merge request contains one single commit, the description of the merge request can be the commit message.
- The Allow commits from members who can merge to the target branch option in the Contribution section must be enabled. With this option, the project maintainers are allowed to push or rework the changes of the merge request in its original location (the user branch).
Once the Submit merge request button is clicked, the process to create the merge request would be finished, and it would be now time for maintainers to review the changes suggested.
The review process
The review of the merge request is done commit by commit, and therefore each commit should be self-contained, in the sense that it should explain clearly the change being done by itself, even if it is part of a series of commits. If this is not done, e.g. if a huge 1000 line commit changing 100 different files at the same time is suggested, it is very likely that the merge request will be rejected. Not because the change is not good, it may be perfectly good, but because it’s not review-able.
Reworking the branch after review
If the maintainer asks for changes to be done, work on them. Don’t add additional commits on top of the original ones for the changes suggested by the maintainer; instead, fixup the changes in the correct commit. It is very suggested that the user knows how to use git commit --fixup
and git commit --squash
, as these are very powerful tools to have the commits right. A simple usage example of --fixup
can be seen in the following snippet, where a quick fix is added on a given already existing commit in 2 steps: first a new fixup commit is created, then an interactive rebase reorders the commits automatically to apply the fixup commit in the correct place:
$ git log --oneline
91b399cd shared-qmi: acquisition order preference TLV always same items
ef55409b shared-qmi: process all feature checks in SSP response together
1a3c3b9e shared-qmi: if getting TP/SSP fails, assume unsupported
c1dc9339 shared-qmi: add missing feature check flag initialization to UNKNOWN
$ git status
On branch my-branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: src/mm-base-modem.c
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a --fixup 1a3c3b9e
my-branch 9788d020] fixup! shared-qmi: if getting TP/SSP fails, assume unsupported
1 file changed, 3 insertions(+), 1 deletion(-)
$ git log --oneline
9788d020 fixup! shared-qmi: if getting TP/SSP fails, assume unsupported
91b399cd shared-qmi: acquisition order preference TLV always same items
ef55409b shared-qmi: process all feature checks in SSP response together
1a3c3b9e shared-qmi: if getting TP/SSP fails, assume unsupported
c1dc9339 shared-qmi: add missing feature check flag initialization to UNKNOWN
$ git rebase -i --autosquash upstream/main
// inside editor, the fixup commit is reordered and setup to fixup
pick c1dc9339 shared-qmi: add missing feature check flag initialization to UNKNOWN
pick 1a3c3b9e shared-qmi: if getting TP/SSP fails, assume unsupported
fixup 9788d020 fixup! shared-qmi: if getting TP/SSP fails, assume unsupported
pick ef55409b shared-qmi: process all feature checks in SSP response together
pick 91b399cd shared-qmi: acquisition order preference TLV always same items
Successfully rebased and updated refs/heads/aleksander/my-branch.
$ git log --oneline
82ca83ad shared-qmi: acquisition order preference TLV always same items
0a24c403 shared-qmi: process all feature checks in SSP response together
0cdbba14 shared-qmi: if getting TP/SSP fails, assume unsupported
c1dc9339 shared-qmi: add missing feature check flag initialization to UNKNOWN
Once the updated branch is considered ready, the user should re-push the branch to the same place, i.e. the origin
remote and the same branch name as was originally used when creating the merge request. If the branch has been re-created (e.g. after applying fixup/squash commits), the user will need to force push it. There is no need to create a full new merge request after updating the branch.
$ git push --force origin my-branch
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 4 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 1.14 KiB | 1.14 MiB/s, done.
Total 5 (delta 4), reused 0 (delta 0), pack-reused 0
remote:
remote: View merge request for my-branch:
remote: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/477
remote:
To gitlab.freedesktop.org:username/ModemManager.git
+ 08c3de0b...9e75a1ff my-branch -> origin/my-branch (forced update)
As seen above, gitlab will provide the link to the already existing merge request that is being updated.
Updating the local branch after a forced push by others
Sometimes the maintainers themselves will do some reworks in the user branch, and ask the user for review of those changes. In that case, the forced push from the previous section may have been done by the maintainers (if the Allows commits from members who can merge to the target branch option has been enabled in the merge request), and the user will need to update the local branch with the latest commits from the remote branch before doing any additional change or in order to locally review the new updates.
The same will be required if the branch is re-created by gitlab itself (e.g. after running Rebase in the merge request page in gitlab).
Synchronizing the remote with the local branch can easily be done with a fetch
operation first (see how the message reports a forced update), and then a hard reset to point the local branch to the new remote one:
$ git fetch origin
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (6/6), 746 bytes | 746.00 KiB/s, done.
From gitlab.freedesktop.org:username/ModemManager.git
+ b0b78e8...693b464 my-branch -> origin/my-branch (forced update)
$ git checkout my-branch
$ git reset --hard origin/my-branch
After the last commit, the local branch will be in sync with the latest contents from the user remote.
Accepting the merge request and merging to main
Once the suggested changes are accepted by the maintainers, one of them will merge the merge request on top of git main. If the changes are bugfixes that apply to older stable releases, the maintainer may also decide to cherry-pick them to the older stable branches. The user should not need to do that at this point.
5.5 - Project communication
Reporting bugs
Bugs should be reported through the FreeDesktop.org gitlab instance:
Suggesting changes or fixes
Changes and fixes should be suggested through the FreeDesktop.org gitlab instance:
- ModemManager merge requests
- libqmi merge requests
- libmbim merge requests
- libqrtr-glib merge requests
Mailing lists
Formal discussion of issues, project features or any general question about the projects should be posted to the corresponding project mailing list. These mailing lists are public and archived for future reference.
Please subscribe to the mailing list before sending new messages, or otherwise each message sent will need to be manually approved by the list administrator.
ModemManager mailing list
Discussions about ModemManager take place on the modemmanager-devel (at) lists.freedesktop.org mailing list:
libqmi mailing list
Discussions about libqmi or libqrtr-glib take place on the libqmi-devel (at) lists.freedesktop.org mailing list:
libmbim mailing list
Discussions about libmbim take place on the libmbim-devel (at) lists.freedesktop.org mailing list:
Matrix and IRC
Informal discussion about the projects can be done in the project Matrix channel at #modemmanager:matrix.org, which is also bridged to the #modemmanager IRC channel in Libera.Chat.
6 - Frequently Asked Questions
This list provides comments and answers to common questions asked in the projects.
Can the projects be installed in /usr/local
instead of /usr
?
Yes, but several things should be considered.
Library lookup with LD_LIBRARY_PATH
All the build examples given for all the projects in this documentation use the --prefix=/usr
switch given to the meson setup
command (or to ./configure
when using GNU autotools) when preparing the build. This prefix is the common one used by distributions when building packages, and so if the user uses the same one, it will end up overwriting the package manager installed files.
In order to avoid overwriting the package manager installed files, the user can avoid giving the explicit --prefix
, and so the default /usr/local
path will be used as prefix. If this approach is taken, the developer can keep the package manager installed libraries in /usr/lib
and the package manager installed command line tools in /usr/bin
, while keeping the custom installed libraries in /usr/local/lib
and the custom installed command line tools in /usr/local/bin
.
Under this scenario, the user can run e.g. the package manager installed mbimcli
in the following way, which will use the package manager installed library from /usr/lib
:
$ /usr/bin/mbimcli
In the same scenario, the user can run the custom installed mbimcli
in the following way, which will use the custom installed library from /usr/local/lib
:
$ LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/mbimcli
But beware because there are distributions like Debian/Ubuntu which add the /usr/local/bin
path to the PATH
environment variable by default, so running the following command would attempt to run the custom installed mbimcli
with the package manager installed library from /usr/lib
(which is obviously a mess and won’t probably work):
$ mbimcli
This complication with the need of the explicit LD_LIBRARY_PATH
is the reason why this guide suggests to overwrite the package manager installed files when installing custom builds.
pkg-config lookup with PKG_CONFIG_PATH
Building a project using as build dependency another project which was installed in /usr/local
will need an explicit PKG_CONFIG_PATH
specifying where the .pc
files are available, e.g.:
$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig meson setup ...
Additional system files
If the project installs additional system files (e.g. systemd service setup, polkit settings, DBus service files) in /usr/local
instead of /usr
, they will be fully ignored. If the changes being installed require updates in these files, it is advised to avoid installing anywhere else than in /usr
.
How long does it take for a merge request or issue review to happen?
New issues and merge requests are reviewed once the current maintainer finds free time. Please be patient.