Category Archives: Development

ModemManager in OpenWRT (take #2)

mm-openwrt

I’ve been lately working on integrating ModemManager in OpenWRT, in order to provide a unique and consolidated way to configure and manage mobile broadband modems (2G, 3G, 4G, Iridium…), all working with netifd.

OpenWRT already has some support for a lot of the devices that ModemManager is able to manage (e.g. through the uqmi, umbim or wwan packages), but unlike the current solutions, ModemManager doesn’t require protocol-specific configurations or setups for the different devices; i.e. the configuration for a modem running in MBIM mode may be the same one as the configuration for a modem requiring AT commands and a PPP session.

Currently the OpenWRT package prepared is based on ModemManager git master, and therefore it supports: QMI modems (including the new MC74XX series which are raw-ip only and don’t support DMS UIM operations), MBIM modems, devices requiring QMI over MBIM operations (e.g. FCC auth), and of course generic AT+PPP based modems, Cinterion, Huawei (both AT+PPP and AT+NDISDUP), Icera, Haier, Linktop, Longcheer, Ericsson MBM, Motorola, Nokia, Novatel, Option (AT+PPP and HSO), Pantech, Samsung, Sierra Wireless (AT+PPP and DirectIP), Simtech, Telit, u-blox, Wavecom, ZTE… and even Iridium and Thuraya satellite modems. All with the same configuration.

Along with ModemManager itself, the OpenWRT feed also contains libqmi and libmbim, which provide the qmicli, mbimcli, and soon the qmi-firmware-update utilities. Note that you can also use these command line tools, even if ModemManager is running, via the qmi-proxy and mbim-proxy setups (i.e. just adding -p to the qmicli or mbimcli commands).

This is not the first time I’ve tried to do this; but this time I believe it is a much more complete setup and likely ready for others to play with it. You can jump to the modemmanager-openwrt bitbucket repository and follow the instructions to include it in your OpenWRT builds:

https://bitbucket.org/aleksander0m/modemmanager-openwrt

The following sections try to get into a bit more detail of which were the changes required to make all this work.

And of course, thanks to VeloCloud for sponsoring the development of the latest ModemManager features that made this integration possible 🙂

udev vs hotplug

One of the latest biggest features merged in ModemManager was the possibility to run without udev support; i.e. without automatically monitoring the device addition and removals happening in the system.

Instead of using udev, the mmcli command line tool ended up with a new --report-kernel-event that can be used to report the device addition and removals manually, e.g.:

$ mmcli --report-kernel-event="action=add,subsystem=tty,name=ttyUSB0"
$ mmcli --report-kernel-event="action=add,subsystem=net,name=wwan0"

This new way of notifying device events made it very easy to integrate the automatic device discovery supported in ModemManager directly via tty and net hotplug scripts (see mm_report_event()).

With the integration in the hotplug scripts, ModemManager will automatically detect and probe the different ports exposed by the broadband modem devices.

udev rules

ModemManager relies on udev rules for different things:

  • Blacklisting devices: E.g. we don’t want ModemManager to claim and probe the TTYs exposed by Arduinos or braille displays. The package includes a USB vid:pid based blacklist of devices that expose TTY ports and are not modems to be managed by ModemManager.
  • Blacklisting ports: There are cases where we don’t want the automatic logic selection to grab and use some specific modem ports, so the package also provides a much shorter list of ports blacklisted from actual modem devices. E.g. the QMI implementation in some ZTE devices is so poor that we decided to completely skip it and fallback to AT+PPP.
  • Greylisting USB serial adapters: The TTY ports exposed by USB serial adapters aren’t probed automatically, as we don’t know what’s connected in the serial side. If we want to have a serial modem, though, the mmcli --scan-modems operation may be executed, which will include the probing of these greylisted devices.
  • Specifying port type hints: Some devices expose multiple AT ports, but with different purposes. E.g. a modem may expose a port for AT control and another port for the actual PPP session, and choosing the wrong one will not work. ModemManager includes a list of port type hints so that the automatic selection of which port is for what purpose is done transparently.

As we’re not using udev when running in OpenWRT, ModemManager includes now a custom generic udev rules parser that uses sysfs properties to process and apply the rules.

procd based startup

The ModemManager daemon is setup to be started and controlled via procd. The init script controlling the startup will also take care of scheduling the re-play of the hotplug events that had earlier triggered --report-kernel-event actions (they’re cached in /tmp); e.g. to cope with events coming before the daemon started or to handle daemon restarts gracefully.

DBus

Well, no, I didn’t port ModemManager to use ubus 🙂 If you want to run ModemManager under OpenWRT you’ll also need to have the DBus daemon running.

netifd protocol handler

When using ModemManager, the user shouldn’t need to know the peculiarities of the modem being used: all modems and protocols (QMI, MBIM, Generic AT, vendor-specific AT…) are all managed via the same single DBus interfaces. All the modem control commands are internal to ModemManager, and the only additional considerations needed are related to how to setup the network interface once the modem is connected, e.g.:

  • PPP: some modems require a PPP session over a serial port.
  • Static: some modems require static IP configuration on a network interface.
  • DHCP: some modems require dynamic IP configuration on a network interface.

The OpenWRT package for ModemManager includes a custom protocol handler that enables the modemmanager protocol to be used when configuring network interfaces. This new protocol handler takes care of configuring and bringing up the interfaces as required when the modem gets into connected state.

Example configuration

The following snippet shows an example interface configuration to set in /etc/config/network.

 config interface 'broadband'
   option device '/sys/devices/platform/soc/20980000.usb/usb1/1-1/1-1.2/1-1.2.1'
   option proto 'modemmanager'
   option apn 'ac.vodafone.es'
   option username 'vodafone'
   option password 'vodafone'
   option pincode '7423'
   option lowpower '1'

The settings currently supported are the following ones:

  • device: The full sysfs path of the broadband modem device needs to be configured. Relying on the interface names exposed by the kernel is never a good idea, as these may change e.g. across reboots or when more than one modem device is available in the system.
  • proto: As said earlier, the new modemmanager protocol needs to be configured.
  • apn: If the connection requires an APN, the APN to use.
  • username: If the access point requires authentication, the username to use.
  • password: If the access point requires authentication, the password to use.
  • pincode: If the SIM card requires a PIN, the code to use to unlock it.
  • lowpower: If enabled, this setting will request the modem to go into low-power state (i.e. IMSI detach and RF off) when the interface is disconnected.

As you can see, the configuration can be used for any kind of modem device, regardless of what control protocol it uses, which interfaces are exposed, or how the connection is established. The settings are currently only IPv4 only, but adding IPv6 support shouldn’t be a big issue, patches welcome 🙂

SMS, USSD, GPS…

The main purpose of using a mobile broadband modem is of course the connectivity itself, but it also may provide many more features. ModemManager provides specific interfaces and mmcli actions for the secondary features which are also available in the OpenWRT integration, including:

  • SMS messaging (both 3GPP and 3GPP2).
  • Location information (3GPP LAC/CID, CDMA Base station, GPS…).
  • Time information (as reported by the operator).
  • 3GPP USSD operations (e.g. to query prepaid balance to the operator).
  • Extended signal quality information (RSSI, Ec/Io, LTE RSRQ and RSRP…).
  • OMA device management operations (e.g. to activate CDMA devices).
  • Voice call control.

Worth noting that not all these features are available for all modem types (e.g. SMS messaging is available for most devices, but OMA DM is only supported in QMI based modems).

TL;DR?

You can now have your 2G/3G/4G mobile broadband modems managed with ModemManager and netifd in your OpenWRT based system.

Naming devices in ModemManager

img_20161006_115415

No more “which is now the index of this modem…?”

DBus object path and index

When modems are detected by ModemManager and exposed in DBus, they are assigned an unique DBus object path, with a common prefix and a unique index number, e.g.:

/org/freedesktop/ModemManager1/Modem/0

This path is the one used by the mmcli command line tool to operate on a modem, so users can identify the device by the full path or just by the index, e.g. this two calls are totally equivalent:

$ mmcli -m /org/freedesktop/ModemManager1/Modem/0
$ mmcli -m 0

This logic looks good, except for the fact that there isn’t a fixed DBus object path for each modem detected: i.e. the index given to a device is the next one available, and if the device is power cycled or unplugged and replugged, a different index will be given to it.

EquipmentIdentifier

Systems like NetworkManager handle this index change gracefully, just by assuming that the exposed device isn’t the same one as the one exposed earlier with a different index. If settings need to be applied to a specific device, they will be stored associated with the EquipmentIdentifier property of the modem, which is the same across reboots (i.e. the IMEI for GSM/UMTS/LTE devices).

User-provided names

The 1.8 stable release of ModemManager will come with support for user-provided names assigned to devices. A use case of this new feature is for example those custom systems where the user would like to assign a name to a device based on the USB port in which it is connected (e.g. assuming the USB hardware layout doesn’t change across reboots).

The user can specify the names (UID, unique IDs) just by tagging in udev the physical device that owns all ports of a modem with the new ID_MM_PHYSDEV_UID property. This tags need to be applied before the ID_MM_CANDIDATE properties, and therefore the rules file should be named before the 80-mm-candidate.rules one, for example like this:

$ cat /lib/udev/rules.d/78-mm-naming.rules

ACTION!="add|change|move", GOTO="mm_naming_rules_end"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.5",ENV{ID_MM_PHYSDEV_UID}="USB1"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.2",ENV{ID_MM_PHYSDEV_UID}="USB2"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.3",ENV{ID_MM_PHYSDEV_UID}="USB3"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.4",ENV{ID_MM_PHYSDEV_UID}="USB4"
LABEL="mm_naming_rules_end"

The value of the new ID_MM_PHYSDEV_UID property will be used in the Device property exposed in the DBus object, and can also be used directly in mmcli calls instead of the path or index, e.g.:

$ mmcli -m USB4
...
 -------------------------
 System | device: 'USB4'
        | drivers: 'qmi_wwan, qcserial'
        | plugin: 'Sierra'
        | primary port: 'cdc-wdm2'
...

Given that the same property value will always be set for the modem in a specific device path, this user provided names may unequivocally identify a specific modem even when the device is power-cycled, unplugged and replugged or even the whole system rebooted.

Binding the property to the device path is just an example of what could be done. There is no restriction on what the logic is to apply the ID_MM_PHYSDEV_UID property, so users may also choose other different approaches.

This support is already in ModemManager git master, and as already said, will be included in the stable 1.8 release, whenever that is.


TL;DR? ModemManager now supports assigning unique names to devices that stay even across full system reboots.

Dell-branded Sierra Wireless 3G/4G modem not online?

dell-dw5570

Your Dell modem not getting online?

It’s not uncommon to find weird mobile broadband modems that for one reason or another don’t end up working as expected with NetworkManager/ModemManager; but the new 3G/4G modems in Dell laptops are at a total different level. These Dell-branded devices are really Sierra Wireless powered modems, e.g. the Dell 5808 is a Sierra Wireless MC7355, or the Dell DW5570 is a Sierra Wireless MC8805.

[UPDATE]
Looks like not only Dell-branded modems are affected by this issue. According to some user reports HP-branded modems like the HP lt4111 (based on the Sierra Wireless EM7355) are also affected by the issue.

Late last year we started to receive several bugreports in the ModemManager and libqmi mailing lists for these kind of devices. Basically, the modem would never get to a proper online mode with the RF transceivers powered and therefore would never even get registered in the mobile network. This was happening to both QMI and MBIM based configurations, and the direct error message reported by libqmi when trying to get into online mode was just… not very very helpful.


  $ sudo qmicli -d /dev/cdc-wdm1 --dms-get-operating-mode
  [/dev/cdc-wdm1] Operating mode retrieved:
    Mode: 'low-power'
    HW restricted: 'no'


  $ sudo qmicli -d /dev/cdc-wdm1 --dms-set-operating-mode=online
  error: couldn't set operating mode: QMI protocol error (3): 'Internal'

The issue was reported to the kernel, assuming that this would likely be a new missing rfkill related setup in newer Dell laptops. One of the users reported in that same bugreport that actually using Sierra’s GobiNet driver instead of qmi_wwan would end up putting the modem in online mode, so just switching drivers during boot would make it work. WTF?

Digging in Sierra’s GobiNet QMI driver

Well, without much hope of finding anything, and given that I had just bought such a Dell modem myself for testing a new “Dell” plugin, I decided to dig into Sierra’s kernel driver sources. Apart from some already known things (e.g. they use the WDA service to set the net data format in new modems instead of the old CTL service), these lines popped:

  if (is9x15)
  {
    // Set FCC Authentication
    result = QMIDMSSWISetFCCAuth( pDev );
    if (result != 0)
    {
      return result;
    }
  }

The Sierra GobiNet driver is sending some magic “FCC auth” command during boot to the modem; which according to the driver sources maps to command 0x555F in the DMS service. Hey I should try that!

Adding the new command support in libqmi wasn’t difficult, so in some minutes I was ready to test it… and worked.

  $ sudo qmicli -d /dev/cdc-wdm1 --dms-get-operating-mode
  [/dev/cdc-wdm1] Operating mode retrieved:
    Mode: 'low-power'
    HW restricted: 'no'


  $ sudo qmicli -d /dev/cdc-wdm1 --dms-set-fcc-authentication
  [/dev/cdc-wdm1] Successfully set FCC authentication


  $ sudo qmicli -d /dev/cdc-wdm1 --dms-get-operating-mode
  [/dev/cdc-wdm1] Operating mode retrieved:
    Mode: 'online'
    HW restricted: 'no'

Support for this is already available automatically when using libqmi and ModemManager git master. It will hit the next stable releases likely as well.

[UPDATE]
These fixes have been already released in ModemManager 1.4.4 and libqmi 1.12.4.

MBIM?

Well, I don’t know if there is any command in MBIM to do the same operation (likely there is in a Sierra-specific service), but one thing we could anyway try to do is to use “QMI embedded in MBIM“, which Bjørn has already tested some times. I’ll try to test that some day, but I’ll need to get another modem as my DW5570 only comes up with a QMI configuration. For now, if you’re stuck with this problem using MBIM, you can likely just select USB configuration #1 using usb_modeswitch and get the modem switched to QMI mode.

[UPDATE]
If your modem is being managed in MBIM and not in QMI, you can now use Collin McMillan’s tool to issue the QMI FCC Auth command embedded in MBIM transactions.

TL;DR?

Dell-branded Sierra Wireless modems need the “FCC Auth” command (QMI DMS service, 0x555F) before they can be brought online; supported in libqmi and ModemManager already.