Sharing a QMI port between processes
A bit of background…
I’ve blogged earlier about how the QMI protocol defines different services and allows to have multiple clients allocated for each service. Allowing multiple clients (i.e. QMI transactions with different client ids) was originally implemented in the protocol to allow multiple user-space applications to talk to the Gobi device, as the original Qualcomm kernel drivers allowed this. In these drivers, the management of client allocations and releases (through the implicit CTL service) was done by the kernel itself, and thus, multiple user-space applications could request new clients at the same time, leaving the work of managing the actual QMI communication with the device to the kernel.
But that is no longer the case with the ‘
qmi_wwan‘ driver available in the upstream Linux kernel. In this case, the implicit CTL service is also managed in user-space, and there should be a single process involved in talking to the QMI port. The side effect of this behavior was that the whole client allocation logic didn’t make much sense any longer, as the process owning the port would be the only one being able to create clients.
Luckily, we designed the libqmi interface in a way that the CTL service was completely hidden to the user of the library. A user would just create a ‘
QmiDevice‘ object, and afterwards allocate new ‘
QmiClient‘ objects using the device object. All the internal CTL service communication between the user-space process and the actual modem device would be run internally by objects we created.
So, with the target of allowing multiple user-space processes to use the same QMI port in mind, a new ‘qmi-proxy‘ daemon was created in libqmi. Whenever a ‘
QmiDevice‘ is opened with the new ‘
QMI_DEVICE_OPEN_FLAGS_PROXY‘ flag, we will try to launch the ‘qmi-proxy’, which will be the only process talking to the actual QMI port. Every other process using the ‘
QMI_DEVICE_OPEN_FLAGS_PROXY‘ flag, including the one which launched the proxy, will now send the QMI requests to the proxy, and receive the QMI responses and indications from the proxy.
In order to implement the proxy-based communication in libqmi’s ‘
QmiDevice‘, we didn’t have to do many changes:
- We extended our implementation of the CTL service with a new ‘Internal Proxy Open’ command, which allows the application to tell the proxy which QMI port wants to use. This command uses the
0xFF00command id, far away from the current set of command ids currently available for the CTL service, so not likely to collide with any new update of the service ever.
- All the communication from and to the proxy are plain QMI commands, including requests and responses in the CTL service. The only critical thing to do was to make sure that the ‘
QmiDevice‘-side CTL transaction ids (i.e. unique CTL transaction in a given process) were translated to the ‘qmi-proxy’-side CTL transaction ids (i.e. unique CTL transaction with the actual device).
- The CTL service is the only one requiring the transaction id translation, as for every other service clients need to be explicitly allocated and released. In other words, different applications will allocate different clients with different client ids, and once they all have its own client id, they can just use the transaction id that they prefer.
- The ‘qmi-proxy’ only analyzes each transferred QMI message in very specific situations. In addition to the CTL transaction id translation mentioned above, the proxy will also take care of forwarding QMI indications (unsolicited messages) to the process owning the client id stated in the indication itself, or to all processes with a client for the service if the ‘broadcast’ client id is used. As an example, a process could request to get notified about signal quality updates via unsolicited “NAS signal info” messages, and the qmi-proxy will make sure that those indications are only sent to the specific process which requested them.
- In order not to use resources when not needed, the ‘qmi-proxy’ is automatically started when first requested, and will be automatically stopped 30s after the last process disappears or releases the last client. We are using a unix socket with an abstract name, so there are no worries of race conditions where proxies are launched at the same time, and no need to make sure that a socket file is never left in the filesystem when the ‘qmi-proxy’ crashes unexpectedly.
- To simplify the logic of the ‘qmi-proxy’, it will not take care of following which QMI ports are available in the system. As with the case of not using the proxy, each application needs to know which ports are available and can be requested to be open. If a port disappears and the proxy still receives requests to that port, it will just return a QMI error to the application which sent the request.
All the previous logic, as said earlier, is managed internally by libqmi and hidden to the user of the library. The key point is to modify your application to use the ‘
ModemManager and qmicli
We also improved the ‘qmicli’ command line interface to allow a new ‘
--device-open-proxy‘ argument (or the shorter ‘
-p‘), which will make use of the new flag to request the ‘qmi-proxy’ to be used. And same for ModemManager; if the version of libqmi is >= 1.7 (currently git master), the new flag will be used by default. We can finally use both ‘qmicli’ and ModemManager at the same time, as ModemManager won’t be the only process owning the port.
But why would anyone want to let other applications use the QMI port? Wouldn’t that collide with the logic of ModemManager?
Well, yes and no. It really depends on which kind of other applications you want to have running alongside ModemManager. If you want to run yet another connection manager, taking care of connecting and disconnecting the QMI port and such, then yes, it will likely collide with ModemManager’s own logic. But that should never be the case. The QMI protocol provides access to tons of features which are not handled by ModemManager, and that is where other applications will benefit from the proxy. Think of custom applications which want to get a deeper view of the status of the radio network using the NAS service, or a GPS application which wants more than what ModemManager provides, or a SIM browser application reading SIM files with the UIM service, or… well, you name it.
When will this be available?
The ‘qmi-proxy’ support is currently available in libqmi git master and is scheduled to be released in version 1.8 some day in the future. We just released 1.6 last week, so it may still take some time.
You can now write applications to use a QMI port with libqmi, even if ModemManager is running.