The mm_base_modem_sync() method is an asynchronous method that
receives a callback and user data, and therefore we MUST always
complete the async method calling that callback. Set that up with a
GTask as usual.
Also, the mm_base_modem_sync_finish() method should be implemented
along with mm_base_modem_sync(), not in the source file of the
caller of the async method. The finish() always depends on how the
async method was implemented, in our case using a GTask.
Under certain rare conditions (e.g. race between querying devices of a
given subsystem and the kernel tearing those devices down), the
subsystem reported for a GUdevDevice seems to be NULL.
So, ensure both subsystem and name are set on the GUdevDevice before we
process them.
The issue has been observed on GUdevDevices listed by
g_udev_client_query_by_subsystem(), not on the ones asynchronously
reported via uevents, but we add the validity check on both places for
consistency.
Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/343
This allows us to know which of the subsystem or name for a
removed device is triggering the assertion from just a stack
trace that contains line information.
Instead of creating new clients internally whenever we need them, just
make sure each MMKernelDeviceUdev object keeps a full reference to the
GUdevClient that generated all GUdevDevices.
There is no point in creating a new kernel device object just to
process a remove event; instead, do any matching with existing
kernel device objects by subsystem and name, which is what the generic
backend already did anyway.
This avoids unnecessary lookup of information in sysfs during removal
events, because the port is anyway already gone when we try to look
those up.
Even if udev support is really built and available.
This is extremely useful to test the udev-less setup without fully
recompiling the whole daemon.
E.g.: the daemon can be run like this:
$ sudo /usr/sbin/ModemManager --debug --test-no-udev
And then, the kernel events may be reported using mmcli like this:
$ sudo mmcli --report-kernel-event-auto-scan
Back in Linux < 3.6 days, the cdc-wdm ports exposed by the QMI driver
were flagged as owned by the 'usb' subsystem. That changed in 3.6 when
the subsystem was renamed to 'usbmisc':
https://mail.gnome.org/archives/networkmanager-list/2012-June/msg00125.html
This patch removes all monitoring of the 'usb' subsystem completely,
which is anyway a valid subsystem but for which we shouldn't need any
special handling. Right now, with newer kernels, we were using that
monitoring exclusively to get notified of full USB device remove
events, which is really not required as we already process the port
removals one by one.
We simplify the logic everywhere that attempted to match either the
'usb' or 'usbmisc' subsystems, and we no longer require the explicit
checks for the port name being named 'cdc-wdm[0-9]*' in the code, as
that is already taken care of by the ID_MM_CANDIDATE udev tag rule.
The auth provider is now a singleton (since 20ab6550), one single
object that lives throughout the whole program execution, and so we
don't need to keep our own full references around. This fix makes
sure we don't attempt to unref a full auth provider reference we
don't own.
Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/179
The auth provider setup is a bit over-engineered. Simplify it by
making a single MMAuthProvider object that may or may not use polkit,
depending on configure options. This object is also setup as a
singleton object using the helper MM_DEFINE_SINGLETON_GETTER().
Instead of having the reference to the object manager server only
while the modem is exported, just keep a reference for as long as the
device object exists. This will make it easier to handle reprobing
logic.
This new method allows users of the ModemManager API to take full
control of a given device.
Unlike other operations in the API, the inhibition is maintained as
long as the caller exists in the bus, or until the same caller
uninhibits the device.
https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/98
This prevents errors due to nasty typos in the strings.
We define all symbols in a single header file that is NOT considered
part of the API, as there is no need for MM clients to know about
these tags code-wise. These tags are only meaningful when associated
to devices in udev.
Information of each tag is included in the general API documentation.
https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/88
Releasing the port on the device looks benign but because it emits
a signal, it could call device_context_port_released and unref the
MMDevice in port_context_unref. This means the MMDevice might be
disposed before we get to the g_object_ref and the subsequent call
to g_hash_table_remove will try to hash a null string, which makes
MM crash.
The hashtable is keyed on the UID of the MMDevice, and its hash
function is g_str_hash. We shouldn't be passing a GObject into
g_hash_table_remove because calling g_str_hash on an MMDevice is
wrong.
All the previous filter rules were applicable per-port independently.
But, we also want to apply rules on a port based on the existence of
other ports on the same device (e.g. allow TTY if the device also has
a NET port). In this case, we need to wait for all ports to appear and
then apply the additional rules.
We re-use the "min wait time" timeout in the plugin-manager for this
same purpose. This timeout is setup to wait for ports to appear before
starting the probing process (e.g. so that plugin filters like the
forbidden-drivers one work). The very same timeout can therefore be
used to check whether we start the probing or not based on additional
filter rules.
The 'default' filter policy was based on blacklisting as much as
possible and otherwise allow.
The new 'strict' filter policy will be based on whitelisting as much
as much as possible, using custom defined rules, and otherwise forbid
the ports.
The new 'paranoid' filter policy is equivalent to the 'strict' filter
after having applied the blacklist rules from the 'default' filter.
Added a new '--filter-policy=[POLICY]' option in the daemon, which
allows selecting between the supported filter policies. For now, only
two policies are defined:
* default: the default policy used by ModemManager, where it tries
to probe and detect as many modem ports as possible.
* whitelist-only: only devices explicitly tagged via udev (with the
ID_MM_DEVICE_PROCESS tag) will be probed and used.
E.g. forcing a MBIM modem to run in AT-only mode:
# MM_FILTER_RULE_NET=0 \
MM_FILTER_RULE_CDC_WDM=0 \
/usr/sbin/ModemManager --debug
This is just for quick testing for now.
This new object allows configuring the filter rules applied to the
device ports. By default, for now, it implements the same rules as the
MMKernelDevice is_candidate() method, which is obsoleted.
==28888== 622 (280 direct, 342 indirect) bytes in 7 blocks are definitely lost in loss record 2,515 of 2,548
==28888== at 0x6474014: g_type_create_instance (in /usr/lib/libgobject-2.0.so.0.5200.3)
==28888== by 0x6455027: ??? (in /usr/lib/libgobject-2.0.so.0.5200.3)
==28888== by 0x6456A54: g_object_newv (in /usr/lib/libgobject-2.0.so.0.5200.3)
==28888== by 0x6457213: g_object_new (in /usr/lib/libgobject-2.0.so.0.5200.3)
==28888== by 0x4E9DD7D: mm_kernel_event_properties_new (mm-kernel-event-properties.c:422)
==28888== by 0x4E9D8BC: mm_kernel_event_properties_new_from_string (mm-kernel-event-properties.c:283)
==28888== by 0x1465D7: process_initial_kernel_events (mm-base-manager.c:555)
==28888== by 0x14679E: mm_base_manager_start (mm-base-manager.c:581)
==28888== by 0x143CF3: name_acquired_cb (main.c:110)
==28888== by 0x616B805: ??? (in /usr/lib/libgio-2.0.so.0.5200.3)
==28888== by 0x616BA47: ??? (in /usr/lib/libgio-2.0.so.0.5200.3)
==28888== by 0x612FD52: ??? (in /usr/lib/libgio-2.0.so.0.5200.3)
When a USB modem is switching its USB configuration, udev may deliver
the remove events of USB interfaces associated with the old USB
configuration and the add events of USB interfaces associated with the new USB
configuration in an interleaved fashion. An interleaved remove event of USB
interface could trigger the special case handling code in
mm-base-manager.c:device_removed() and incorrectly remove a MMDevice under
probing.
See https://lists.freedesktop.org/archives/modemmanager-devel/2017-August/005626.html
for more details.
This patch adds a check to ensure that only remove events of USB
device (i.e. not interface) can trigger the special handling code.
Looks like the preprocessor doesn't choke when using #if WITH_UDEV and
it isn't defined to any value, but anyway, better explicitly say that
we're checking if it's defined or not.
Since commit e9d0989ed0, the MMDevice may be removed from the
tracking hash table when the support check operation fails to create a
modem object.
If this failure happens due to the port probe cancellations requested
during the udev removal event for a given device port, we would end up
using an already disposed object and triggering a segfault.
This fix just makes sure a full valid reference to the MMDevice object
is kept around until we're done using it.
[mm-base-manager.c:216] device_removed(): (usbmisc/cdc-wdm1): released by device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4'
[mm-plugin-manager.c:1131] device_context_port_released(): [plugin manager] task 5: port released: cdc-wdm1
[mm-base-manager.c:216] device_removed(): (tty/ttyACM0): released by device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4'
[mm-plugin-manager.c:1131] device_context_port_released(): [plugin manager] task 5: port released: ttyACM0
[mm-base-manager.c:221] device_removed(): Removing empty device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4'
[mm-plugin-manager.c:1219] device_context_cancel(): [plugin manager) task 5: cancellation requested
[mm-plugin-manager.c:979] device_context_continue(): [plugin manager] task 5: no more ports to probe
[mm-plugin-manager.c:813] device_context_complete(): [plugin manager] task 5: finished in '0.090510' seconds
[mm-base-manager.c:172] device_support_check_ready(): Couldn't check support for device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4': Operation was cancelled
[mm-base-manager.c:223] device_removed(): Device support check has been cancelled
Thread 1 "ModemManager" received signal SIGSEGV, Segmentation fault.
0x00007ffff6543c50 in g_str_hash () from /usr/lib/libglib-2.0.so.0
(gdb) bt
#0 0x00007ffff6543c50 in g_str_hash () at /usr/lib/libglib-2.0.so.0
#1 0x00007ffff6542b2d in () at /usr/lib/libglib-2.0.so.0
#2 0x0000000000439675 in device_removed (self=0x770900, kernel_device=0x763e60) at mm-base-manager.c:225
#3 0x0000000000439e70 in handle_uevent (client=0x769c20, action=0x81d910 "remove", device=0x7fffe4001c40, user_data=0x770900) at mm-base-manager.c:415
#4 0x00007ffff54c61c8 in ffi_call_unix64 () at /usr/lib/libffi.so.6
#5 0x00007ffff54c5c2a in ffi_call () at /usr/lib/libffi.so.6
#6 0x00007ffff682d7ae in g_cclosure_marshal_generic ()
at /usr/lib/libgobject-2.0.so.0
#7 0x00007ffff682cf75 in g_closure_invoke () at /usr/lib/libgobject-2.0.so.0
#8 0x00007ffff683ef82 in () at /usr/lib/libgobject-2.0.so.0
#9 0x00007ffff6847bcc in g_signal_emit_valist ()
at /usr/lib/libgobject-2.0.so.0
#10 0x00007ffff6847faf in g_signal_emit () at /usr/lib/libgobject-2.0.so.0
#11 0x00007ffff7023c74 in () at /usr/lib/libgudev-1.0.so.0
#12 0x00007ffff655445a in g_main_context_dispatch ()
at /usr/lib/libglib-2.0.so.0
#13 0x00007ffff6554810 in () at /usr/lib/libglib-2.0.so.0
#14 0x00007ffff6554b32 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#15 0x0000000000437bf5 in main (argc=2, argv=0x7fffffffeb28) at
main.c:180
(gdb) fr 2
#2 0x0000000000439675 in device_removed (self=0x770900, kernel_device=0x763e60) at mm-base-manager.c:225
225 g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
(gdb) p mm_device_get_uid (device)
$1 = (const gchar *) 0x0
(gdb) p *device
$3 = {parent = {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0}, priv = 0x7feb20}
If the device support check fails, either with an error, or afterwards
when trying to create a modem object, we must remove the MMDevice from
the tracking table of devices, so that a manual scan request
afterwards re-scans all ports.
https://bugs.freedesktop.org/show_bug.cgi?id=100157
Instead of relying on the udev daemon and GUDev to manage the devices reported
by the kernel, we can now run ModemManager relying solely on the kernel events
reported via the new ReportKernelEvent() API. Therefore, the '--no-auto-scan'
option is implicit for the ModemManager daemon when udev is disabled in the
build.
Additionally, a new custom implementation of the kernel device object is
provided, which uses sysfs to load the properties and attributes required in
each kernel device, instead of using a GUdevDevice.
The udev rule files are kept in place, and a simple custom parser is provided
which preloads all rules in memory once and then applies them to the different
kernel objects reported via ReportKernelEvent(), e.g. to set port type hints.
A simple unit test setup is prepared to validate the udev rules during the
`check' Makefile target.
This commit enables a new core ModemManager daemon option, so that automatic
detection of available modems is totally disabled: '--no-auto-scan'. Note that
this option also replaces the previously used '--test-no-auto-scan' option,
which was only used during tests.
Along with the new ModemManager option, a new ReportKernelEvent() method in
the API is defined, which allows notifying the daemon of which interfaces it
should be accessing, as well as the main details of each interface. The only
mandatory parameters in the new method are 'action' (add/remove), 'name' (the
name of the interface) and 'subsystem' (the subsystem of the interface).
The mmcli tool has support for using the new api method via several new options:
* The '--report-kernel-event' option allows specifying device ports one by
one, and is a direct mapping of the ReportKernelEvent() method:
$ sudo mmcli --report-kernel-event="action=add,name=wwan0,subsystem=net"
$ sudo mmcli --report-kernel-event="action=add,name=cdc-wdm0,subsystem=usbmisc"
* The '--report-kernel-event-auto-scan' option uses udev monitoring to notify
events automatically to the daemon. This allows to operate in a way
equivalent to the default daemon operation (with implicit auto-scan).
Worth noting that the ReportKernelEvent() method is only usable when
'--no-auto-scan' is explicitly used in the daemon. An error will be reported if
the method is tried while standard udev monitoring is enabled (implicit if
auto scan isn't explicitly disabled in the daemon).
If mmcli is going to be used only to report 'real time' events, an optional
'--initial-kernel-events=[PATH]' may be given in the ModemManager call to
automatically process a set of port kernel events one by one on boot. The file
may e.g. contain:
action=add,name=wwan0,subsystem=net
action=add,name=cdc-wdm0,subsystem=usbmisc
Instead of relying constantly on GUdevDevice objects reported by GUdev, we now
use a new generic object (MMKernelDevice) for which we provide an initial GUdev
based backend.
All ports of the same modem reported by the kernel will all be associated with
a common 'uid' (unique id), which uniquely identifies the physical device. This
logic was already in place, what we do now is avoid calling it the 'sysfs
path' of the physical device, because we may not want to use that to identify
a device.
This logic now also enables the possibility of "naming" the modems in a unique
way by setting the "ID_MM_PHYSDEV_UID" property in the "usb_device" that owns
all the ports.
E.g. a custom device has 4 modems in 4 different USB ports. The device path of
each USB device will always be the same, so the naming rules could go like this:
$ vim /usr/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.1", ENV{ID_MM_PHYSDEV_UID}="USB-MODEM-1"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.2", ENV{ID_MM_PHYSDEV_UID}="USB-MODEM-2"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.3", ENV{ID_MM_PHYSDEV_UID}="USB-MODEM-3"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5.4", ENV{ID_MM_PHYSDEV_UID}="USB-MODEM-4"
LABEL="mm_naming_rules_end"
Each of the modems found will have a unique UID retrieved from the previous list
of rules. Then, "mmcli" has also been updated to allow using the UID instead of
the modem DBus path or index, e.g.:
$ sudo mmcli -m USB-MODEM-1
/org/freedesktop/ModemManager1/Modem/0 (device id '988d83252c0598f670c2d69d5f41e077204a92fd')
-------------------------
Hardware | manufacturer: 'ZTE CORPORATION'
| model: 'MF637'
| revision: 'BD_W7P673A3F3V1.0.0B04'
| supported: 'gsm-umts'
| current: 'gsm-umts'
| equipment id: '356516027657837'
-------------------------
System | device: 'USB-MODEM-1'
| drivers: 'option'
| plugin: 'ZTE'
| primary port: 'ttyUSB5'
| ports: 'ttyUSB5 (at)'
...
$ sudo mmcli -m USB-MODEM-1 --enable
...