Monthly Archives: August 2012
Linux 3.2 kernel with QMI support
When I started to develop the QMI support in OpenWRT, latest trunk was based on the 3.2 kernel series. By the time you read this, OpenWRT may already have a recent enough kernel (>= 3.4), so this custom setup may not be needed any more, so keep it just for reference.
The ‘v3.2.5-qmi’ branch in the Lanedo stable kernel tree contains a set of patches on top of the 3.2.5. Linux kernel release. These patches add support for QMI ports (updated ‘cdc-wdm’ and new ‘qmi_wwan’ driver) in the 3.2 stable series:
OpenWRT with QMI support
The same set of patches was then added to the ‘qmi-support’ branch of the Lanedo openwrt tree, enabling OpenWRT builds with QMI support:
When you compile this OpenWRT build, make sure you configure the kernel with the QMI-specific requirements enabled:
libqmi-glib and qmi4g
‘libqmi-glib’ and ‘qmi4g’ are two new packages added to the ‘qmi-support’ branch of the Lanedo openwrt-packages tree:
This repository can be added to your OpenWRT build by creating a new ‘
feeds.conf‘ with the following contents:
src-git packages git://gitorious.org/lanedo/openwrt-packages.git;qmi-support
The new packages, in detail:
- libqmi-glib: This package provides a preliminary version of
libqmi-glib, as released unofficially by me. This package will provide the
qmiclicommand line utility and the
- qmi4g: This package registers a new ‘
qmi4g‘ network protocol, which takes care of launching the network start/stop requests through QMI.
If you’re using the precompiled OpenWRT images I gave above, you can just install these packages using ‘opkg’ once you’ve added the ‘latest’ Lanedo repository.
qmi4g package is installed, you are then allowed to include the
following configuration under /etc/config/network:
config 'interface' 'broadband'
option 'ifname' 'wwan0'
option 'proto' 'dhcp'
option 'auto' '0'
config 'interface' 'wdm0'
option 'proto' 'qmi4g'
option 'wdmif' '/dev/cdc-wdm0'
option 'wwanif' 'broadband'
The configuration is split into 2 interfaces:
- First, the configuration for the ‘
wwan0‘ interface. This interface needs to be set with ‘
auto‘ equal to ‘
0‘, so that it is never brought up automatically; and with ‘
dhcp‘ as the protocol to be used. You should never ifup/ifdown this interface manually.
- Second, a virtual interface using the new ‘
qmi4g‘ protocol, which needs 2 options set: ‘
wdmif‘ with the cdc-wdm port to use for the QMI protocol, and ‘
wwanif‘ with the uci-interface-name of the wwan iface to use.
Start/Stop the network
Once the qmi4g setup is added in /etc/config/network, you can now then just:
$> ifup wdm0
That command will internally first launch the network start QMI command, and if succeeds it will itself ifup wwan0. The wwan interface can be used as any other eth-based interface now, it can be added as part of multiwan or in a vlan or in a bonding, or anything.
Once the connection is no longer wanted, you can just:
$> ifdown wdm0
That command will stop the network with QMI and also ifdown wwan0.
Once the network configuration is in place, the connection can also be started via web. Just log in to LUCI, go to Network interfaces and you’ll see both the wwan interface (“broadband“) and the virtual “wdm0“. Starting/Stopping the “wdm0” interface via LUCI should work. As said before, you shouldn’t touch the wwan interface directly.
What is QMI?
QMI is a binary protocol designed to replace the AT command based communication with modems, and is available in devices with Qualcomm chipsets from multiple vendors (Novatel, Huawei, Sierra Wireless, ZTE… and of course Qualcomm itself).
The protocol defines different ‘services‘, each of them related to different actions that may be requested to the modem. For example, the ‘DMS’ (Device Management) service provides actions to load device information; while the ‘NAS’ (Network Access) service provides actions to register in the network. Similarly, other services will allow the user to request data connections (WDS), setup GPS location reporting (PDS), or manage internals of the user identity module (UIM service). The user needs to handle the creation of ‘clients’ for those services by allocating/deallocating ‘client IDs’ using the generic always-on ‘control’ (CTL) service.
Each service in the protocol defines ‘Request and Responses‘ as well as ‘Indications‘. Each pair of request/response has a maching ID which lets the user concatenate multiple requests and get out-of-order responses that can be afterwards matched through the common ID. Indications arrive as unsolicited messages, sent either to a specific client or as a broadcast message to all the clients of a given service. Usually the user needs to request the enabling of the indications to receive via some request/response.
Finally, each message in the protocol defines a set of input (in requests) and output (in responses and indications) arguments, which we name as TLVs. Some of these are defined to be mandatory, others are optional, and others are only mandatory if some other argument is available and has a given value. For example, some output arguments in response messages are only mandatory if the result of the response (given as a TLV) is SUCCESS.
Using the QMI protocol
This protocol is easily accessible in recent enough Linux kernels (>= 3.4), through the cdc-wdm and qmi_wwan drivers. Once these drivers are in place and the modem gets plugged in, the kernel will expose a new
/dev/cdc-wdm device which can talk QMI, along with a
wwan interface associated to each QMI port.
libqmi is an on-going effort to get a library providing easy access to Qualcomm’s ‘QMI’ protocol. The current libqmi available is based on the GLib/GObject/GIO-powered ‘libqmi-glib’. libqmi tries to ease the use of the protocol by providing:
- A ‘
QmiDevice‘ object to control the access to the /dev/cdc-wdm device. This object allows creating new per-service ‘QmiClient’s. It also hides the use of the implicit ‘CTL’ service client.
- The ‘
QmiClient‘ object provides an interface to the set of request/responses of a given service. Users of the library will just need to execute a GIO-asynchronous method to send the request and get the processed response.
- The ‘
QmiClient‘ object also provides signals for each of the indications given in the service.
- The input and output arguments needed in requests, responses and indications are compiled into ‘bundles’. These bundles are opaque structs with accessors for their elements, which allow us to add new TLVs to a given message in the future without breaking API/ABI.
The protocol is written in the library as a JSON dictionary of rules, and most of the code to handle the protocol in the library is autogenerated during compilation. If you want to take a look at the currently available interface, check the gtk-doc documentation at: http://www.freedesktop.org/software/libqmi/libqmi-glib/latest/
The libqmi project comes with a command line utility (
qmicli) primarily used as a developer tool for testing the libqmi-glib library. Just run the program with ‘
--help-all‘ to get all possible actions it can run. A quick example of usage:
$> sudo qmicli -d /dev/cdc-wdm0 --dms-get-manufacturer
[/dev/cdc-wdm0] Device manufacturer retrieved:
Manufacturer: 'Qualcomm Incorporated'
Hint: If you compile the project passing
CFLAGS, it will dump as DEBUG logs the content and translation of all the QMI messages passed in both directions. You’ll also need ‘
--verbose‘ or just ‘
-v‘ to show the debug logs when running
The project also comes with a small bash script called ‘
qmi-network‘, which allows you to launch a broadband connection using
qmicli. This script requires two arguments; first the cdc-wdm device to talk to, and secondly the action (start|stop|status) to execute. The script can definitely be improved in multiple ways (e.g. send PIN), so if anyone wants to do it patches are very welcome.
Where do I get it?
The project is currently available in the freedesktop.org infrastructure:
- git: http://cgit.freedesktop.org/libqmi
- mailing list: http://lists.freedesktop.org/mailman/listinfo/libqmi-devel
- bugzilla: https://bugs.freedesktop.org/buglist.cgi?product=libqmi
ModemManager has QMI support through libqmi-glib since release 1.0.
Help! Contribute! Sponsor!
If you want to help, or sponsor further development in libqmi, qmicli or the ModemManager integration, just let me know!
[UPDATE] Links updated, along with ModemManager related info.