Age | Commit message (Collapse) | Author |
|
|
|
Use GTask API in place of the deprecated GSimpleAsyncResult.
|
|
|
|
The BUFFER_FULL signal handler is effectively working in the same way
as the response buffer processor, in both cases we may have scheduled
the completion of the serial command, and that in turn may end up
fully disposing the port object. We must make sure the port object is
valid for as long as we need it in this function, so we take a
reference while processing the response buffer.
Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/535
|
|
wwan qcdm port is not a serial port, calling config_fd on it
will always fail, i.e.:
ModemManager[124587]: <debug> [1619584182.125262] [wwan0p1QCDM/probe] probing QCDM...
ModemManager[124587]: <debug> [1619584182.125398] [wwan0p1QCDM/qcdm] opening serial port...
ModemManager[124587]: <debug> [1619584182.151759] [wwan0p1QCDM/qcdm] failed to configure serial device
ModemManager[124587]: <warn> [1619584182.151836] [wwan0p1QCDM/qcdm] failed to open serial device
ModemManager[124587]: <warn> [1619584182.170152] [plugin-manager] task 1,wwan0p1QCDM: error when checking support with plugin 'generic': (wwan/wwan0p1QCDM) Failed to open QCDM port: Failed to open QCDM port: -2
|
|
|
|
|
|
The bits/parity/stopbits serial settings are set by the daemon, so if
any of them are not expected, assert, not just warn.
|
|
mm-port-serial.c: In function ‘port_serial_process_command’:
mm-port-serial.c:605:16: error: this statement may fall through [-Werror=implicit-fallthrough=]
605 | if (written > 0) {
| ^
mm-port-serial.c:611:9: note: here
611 | case G_IO_STATUS_AGAIN:
| ^~~~
|
|
mm-port-serial.c: In function ‘_close_internal’:
mm-port-serial.c:1464:19: error: comparison of integer expressions of different signedness: ‘int’ and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
1464 | for (i = 0; i < g_queue_get_length (self->priv->queue); i++) {
| ^
|
|
mm-port-serial.c: In function ‘port_serial_process_command’:
mm-port-serial.c:594:9: error: switch missing default case [-Werror=switch-default]
594 | switch (write_status) {
| ^~~~~~
mm-port-serial.c: In function ‘parse_response_buffer’:
mm-port-serial.c:925:5: error: switch missing default case [-Werror=switch-default]
925 | switch (MM_PORT_SERIAL_GET_CLASS (self)->parse_response (self,
| ^~~~~~
|
|
When a flash operation is started, it is always scheduled in an idle.
If this operation is cancelled, we should right away un-schedule it,
otherwise we may end up calling flash_do() with the GTask in the
private info already gone.
See https://gitlab.freedesktop.org/mobile-broadband/ModemManager/merge_requests/178#note_330017
|
|
|
|
If the reopening operation fails when attempting to recover the
previous open count, it could mean the port is already gone. We didn't
get a HUP in the TTY because the channel I/O monitoring isn't in place
during this time, so this is the best way to detect that at this
point.
And if we do see an error, we'll flag the port as forced closed so
that we do not attempt to reopen it again.
ModemManager[4219]: <debug> [1568123246.421399] Disconnecting bearer '/org/freedesktop/ModemManager1/Bearer/0'
ModemManager[4219]: <info> [1568123246.421465] Modem /org/freedesktop/ModemManager1/Modem/0: state changed (connected -> disconnecting)
ModemManager[4219]: <debug> [1568123246.421698] Reopening data port (modemu)...
ModemManager[4219]: <debug> [1568123246.421722] (modemu) reopening port (2)
ModemManager[4219]: <debug> [1568123246.421740] (modemu) device open count is 1 (close)
ModemManager[4219]: <debug> [1568123246.421754] (modemu) device open count is 0 (close)
ModemManager[4219]: <debug> [1568123246.421770] (modemu) closing serial port...
ModemManager[4219]: <debug> [1568123246.421786] (modemu): port now disconnected
ModemManager[4219]: <debug> [1568123246.421816] (modemu) serial port closed
ModemManager[4219]: <info> [1568123248.028573] (tty/modemu): released by device '/sys/devices/pci0000:00/0000:00:00.0'
ModemManager[4219]: <debug> [1568123248.028637] Removing empty device '/sys/devices/pci0000:00/0000:00:00.0'
ModemManager[4219]: <debug> [1568123248.028866] Removing from DBus bearer at '/org/freedesktop/ModemManager1/Bearer/0'
ModemManager[4219]: <debug> [1568123248.028914] [device /sys/devices/pci0000:00/0000:00:00.0] unexported modem from path '/org/freedesktop/ModemManager1/Modem/0'
ModemManager[4219]: <debug> [1568123248.028944] Periodic signal checks disabled
ModemManager[4219]: <debug> [1568123256.401738] Connection monitoring is unsupported by the device
ModemManager[4219]: <debug> [1568123256.422939] (modemu) opening serial port...
ModemManager[4219]: <warn> [1568123256.423062] (modemu) could not open serial device (2)
ModemManager[4219]: <debug> [1568123256.423104] Couldn't disconnect bearer '/org/freedesktop/ModemManager1/Bearer/0': Couldn't reopen port (0): Could not open serial device modemu: No such file or directory
ModemManager[4219]: _close_internal: assertion 'self->priv->open_count > 0' failed
Thread 1 "ModemManager" received signal SIGTRAP, Trace/breakpoint trap.
0x00007ffff77894e6 in ?? () from /usr/lib/libglib-2.0.so.0
(gdb)
(gdb) bt
#0 0x00007ffff77894e6 in () at /usr/lib/libglib-2.0.so.0
#1 0x00007ffff7789738 in g_logv () at /usr/lib/libglib-2.0.so.0
#2 0x00007ffff777ff80 in g_log () at /usr/lib/libglib-2.0.so.0
#3 0x0000555555661115 in _close_internal (self=0x555555796380, force=0) at mm-port-serial.c:1378
#4 0x0000555555661865 in mm_port_serial_close (self=0x555555796380) at mm-port-serial.c:1503
#5 0x00005555556078cc in ports_context_unref (ctx=0x5555557c4ca0) at mm-broadband-modem.c:9801
#6 0x000055555560e33a in finalize (object=0x5555557a4250) at mm-broadband-modem.c:11940
#7 0x00007ffff787b351 in g_object_unref () at /usr/lib/libgobject-2.0.so.0
#8 0x00005555555b1c71 in detailed_disconnect_context_free (ctx=0x555555785000) at mm-broadband-bearer.c:1369
#9 0x00007ffff795d62a in () at /usr/lib/libgio-2.0.so.0
#10 0x00007ffff787b351 in g_object_unref () at /usr/lib/libgobject-2.0.so.0
#11 0x00005555555b2532 in data_reopen_3gpp_ready (data=0x555555796380, res=0x55555573a580, task=0x55555573a040) at mm-broadband-bearer.c:1605
#12 0x00007ffff795d584 in () at /usr/lib/libgio-2.0.so.0
#13 0x00007ffff7962a87 in () at /usr/lib/libgio-2.0.so.0
#14 0x0000555555661bc6 in reopen_do (self=0x555555796380) at mm-port-serial.c:1607
#15 0x00007ffff778e3c4 in () at /usr/lib/libglib-2.0.so.0
#16 0x00007ffff778ebb0 in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#17 0x00007ffff7790b11 in () at /usr/lib/libglib-2.0.so.0
#18 0x00007ffff7791a63 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#19 0x000055555559afb0 in main (argc=3, argv=0x7fffffffea58) at main.c:181
|
|
We cannot complete the flash task cancellation right away because this
may be called from within _close_internal() during a forced port close
after the TTY has gone, which would mean the object is fully disposed
already after the flash cancellation has been requested.
By making the task cancellation complete in idle, we're sure that
there will be at least one reference valid (the one in the task)
during the port close operation.
ModemManager[25156]: <debug> [1568121341.696563] Modem (Generic) '/sys/devices/pci0000:00/0000:00:00.0' completely disposed
**
ERROR:mm-port-serial.c:2067:finalize: assertion failed: (self->priv->iochannel == NULL)
(gdb) bt
#0 0x00007ffff757c755 in raise () at /usr/lib/libc.so.6
#1 0x00007ffff7567851 in abort () at /usr/lib/libc.so.6
#2 0x00007ffff7741062 in () at /usr/lib/libglib-2.0.so.0
#3 0x00007ffff776d99d in g_assertion_message_expr () at /usr/lib/libglib-2.0.so.0
#4 0x0000555555662f0a in finalize (object=0x55555577a380) at mm-port-serial.c:2067
#5 0x0000555555664d81 in finalize (object=0x55555577a380) at mm-port-serial-at.c:632
#6 0x00007ffff787b351 in g_object_unref () at /usr/lib/libgobject-2.0.so.0
#7 0x00007ffff795d5eb in () at /usr/lib/libgio-2.0.so.0
#8 0x00007ffff787b351 in g_object_unref () at /usr/lib/libgobject-2.0.so.0
#9 0x0000555555662126 in mm_port_serial_flash_cancel (self=0x55555577a380) at mm-port-serial.c:1747
#10 0x0000555555661224 in _close_internal (self=0x55555577a380, force=1) at mm-port-serial.c:1397
#11 0x000055555566197b in port_serial_close_force (self=0x55555577a380) at mm-port-serial.c:1526
#12 0x000055555565fbe5 in common_input_available (self=0x55555577a380, condition=(G_IO_IN | G_IO_ERR | G_IO_HUP)) at mm-port-serial.c:971
#13 0x00005555556600c0 in iochannel_input_available (iochannel=0x55555578a0a0, condition=(G_IO_IN | G_IO_ERR | G_IO_HUP), data=0x55555577a380) at mm-port-serial.c:1073
#14 0x00007ffff778ebb0 in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#15 0x00007ffff7790b11 in () at /usr/lib/libglib-2.0.so.0
#16 0x00007ffff7791a63 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#17 0x000055555559afb0 in main (argc=3, argv=0x7fffffffea58) at main.c:181
|
|
If the signal is automatically disconnected during object disposal, we
shouldn't explicitly try to disconnect it ourselves during finalize().
Reported by: Lubomir Rintel <lkundrak@v3.sk>
|
|
By default all the commands we were sending through the serial port
were added at the tail of the pending queue, but we may want to queue
them at the head in very specific cases (e.g. while sending an SMS).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MMFlowControl is a flags enumeration, so change the property type to
match that, or we'll end up with nasty criticals during runtime.
(ModemManager:30758): GLib-GObject-CRITICAL **: 10:54:26.435: g_param_spec_enum: assertion 'G_TYPE_IS_ENUM (enum_type)' failed
Thread 1 "ModemManager" received signal SIGTRAP, Trace/breakpoint trap.
0x00007ffff71f2a96 in ?? () from /usr/lib/libglib-2.0.so.0
(gdb) bt
#0 0x00007ffff71f2a96 in () at /usr/lib/libglib-2.0.so.0
#1 0x00007ffff71f3def in g_logv () at /usr/lib/libglib-2.0.so.0
#2 0x00007ffff71f3fe0 in g_log () at /usr/lib/libglib-2.0.so.0
#3 0x00007ffff72d90ac in g_param_spec_enum () at /usr/lib/libgobject-2.0.so.0
#4 0x000055555564caf2 in mm_port_serial_class_init (klass=0x5555557607c0) at mm-port-serial.c:2101
#5 0x000055555564759a in mm_port_serial_class_intern_init (klass=0x5555557607c0) at mm-port-serial.c:49
#6 0x00007ffff72ea9b4 in g_type_class_ref () at /usr/lib/libgobject-2.0.so.0
#7 0x00007ffff72eab5a in g_type_class_ref () at /usr/lib/libgobject-2.0.so.0
#8 0x00007ffff72d0f53 in g_object_new_valist () at /usr/lib/libgobject-2.0.so.0
#9 0x00007ffff72d103a in g_object_new () at /usr/lib/libgobject-2.0.so.0
#10 0x000055555564e187 in mm_port_serial_at_new (name=0x55555576e280 "ttyUSB4", subsys=MM_PORT_SUBSYS_TTY) at mm-port-serial-at.c:533
#11 0x0000555555602512 in serial_open_at (self=0x555555715390) at mm-port-probe.c:1285
#12 0x00007ffff71ecb49 in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#13 0x00007ffff71ecf59 in () at /usr/lib/libglib-2.0.so.0
#14 0x00007ffff71ed272 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#15 0x00005555555957e0 in main (argc=3, argv=0x7fffffffe458) at
main.c:181
Also, rename the property to match the naming convention of other
properties in the same object.
|
|
Add flow control property to the MMPortSerial class, and use it when
setting the port flow control.
|
|
After the tty is opened, the fd is passed off to a GIOChannel which
manages it. When the serial port is closed with _close_internal(),
g_io_channel_shutdown() is called which then calls g_io_unix_close() which
in turn close()s the fd.
_close_internal() performs a second explicit close() after the
g_io_channel_shutdown() which *in the best case scenario* will fail with
EBADF.
This is a race condition that can result in other file descriptors being
closed.
This change avoids double closing the serial port fd -- the shutdown() call
is removed in favour of the explicit close().
|
|
If the GCancellable is already cancelled when trying to connect a
signal, the callback given will be run right away, and that may end up
completing the async task and removing the last MMPortSerial
reference.
==30627== Invalid write of size 8
==30627== at 0x1ED43B: port_serial_queue_process (mm-port-serial.c:812)
==30627== by 0x66DE342: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DD8C4: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDC87: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDFA1: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x143F9B: main (main.c:180)
==30627== Address 0xf6f0e98 is 200 bytes inside a block of size 328 free'd
==30627== at 0x4C2E14B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30627== by 0x64742B2: g_type_free_instance (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x1ED0F2: port_serial_got_response (mm-port-serial.c:704)
==30627== by 0x1ED21B: port_serial_response_wait_cancelled (mm-port-serial.c:757)
==30627== by 0x60E1A81: g_cancellable_connect (in /usr/lib/libgio-2.0.so.0.5200.3)
==30627== by 0x1ED43A: port_serial_queue_process (mm-port-serial.c:812)
==30627== by 0x66DE342: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DD8C4: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDC87: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDFA1: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x143F9B: main (main.c:180)
==30627== Block was alloc'd at
==30627== at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30627== by 0x66E3028: g_malloc (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66FAB25: g_slice_alloc (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66FAFB8: g_slice_alloc0 (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x6473FB5: g_type_create_instance (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x6455027: ??? (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x6456DBC: g_object_new_valist (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x6457200: g_object_new (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x1F253A: mm_port_serial_at_new (mm-port-serial-at.c:533)
==30627== by 0x1AC7E7: serial_open_at (mm-port-probe.c:1210)
==30627== by 0x66DD8C4: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDC87: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
|
|
So MM can use them when opening a specific serial port.
Signed-off-by: Javier Viguera <javier.viguera@digi.com>
|
|
We won't set XON/XOFF by default and we won't allow setting RTS/CTS
via a property. The serial port by default starts with no flow control
configured.
|
|
|
|
The method takes care of looping if EAGAIN errors happen, as well as
checking whether all attributes were set or not.
|
|
A new 'ID_MM_TTY_BAUDRATE' per-port udev tag is introduced, which
allows specifying the baudrate that will be used when opening a
specific serial port.
E.g.:
ACTION!="add|change|move", GOTO="mm_my_modem_end"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.3/*", ENV{ID_MM_TTY_BAUDRATE}="115200"
LABEL="mm_my_modem_end"
https://bugs.freedesktop.org/show_bug.cgi?id=100158
|
|
|
|
The g_socket_receive() method returns a signed size variable, so don't
use an unsigned variable to hold the result.
|
|
|
|
Port serial command completions may be performed in several different places:
* When a cached response is set during command sending.
* When errors happen during command sending.
* When we process a response (i.e. common_input_available())
* When we process a timeout (i.e. port_serial_timed_out())
* When cancelled (i.e. port_serial_response_wait_cancelled())
We're currently safe with the previous logic only because the users of the
serial port explicitly complete operations in idle, which means that whenever
we're processing in a internal callback (e.g. during response or timeout
processing) the serial port object is valid for as long as the callback runs.
But, if we ever end up using the serial port with a not-in-idle completion,
it may happen that if the command is completed within a internal signal callback
the serial port object may get fully closed and unref-ed before exiting the
callback.
We could force a valid port reference to exist as long as the internal signal
is scheduled, but then we may lose the ability to automatically close the port
during a full unref(), as the internal signals are set as long as the port is
open.
So, to cope with this possibility of not-in-idle completion, we instead force
references to be valid whenever we see that a command completion may happen,
which is basically whenever port_serial_got_response() is called; but we only
do that if we're going to use the port object after that, otherwise, we ignore
the problem.
In addition to the problems with the references, we also update the
common_input_available() method so that the source isn't kept if the last
response buffer processing ended up closing the port.
|
|
|
|
Response parsing was being done in different places for AT and QCDM subclasses;
in the case of AT it was being done early, before returning the byte array in
the mm_serial_port_command_finish() response. In the case of QCDM, it was being
done after mm_serial_port_command_finish(), and that was forcing every caller to
cleanup the response buffer once the response was processed.
With the new logic in this patch, the response is always parsed (i.e. looked for
a valid response or an error detected) before mm_serial_port_command_finish()
returns, and actually this method now returns a totally different GByteArray,
not the internal response buffer GByteArray, so there's no longer any need for
the caller to explicitly clean it up. The one doing the cleanup is the parser
method itself in every case.
This change also allows us to return serial port responses in idle, but that's
not changed for now as there's no immediate need.
|
|
When valid responses were returned to the caller of the serial command, the
caller itself was responsible for removing from the GByteArray the data that
it was successfully processed (all the data in AT, just 1 message in QCDM). But,
the same logic was missing for the case of errors; we were not explicitly
removing the response and therefore in some cases we would see it propagated
into the next command response. It was common to see this issue when the echo
removal was disabled in the serial port, as in Option/HSO modems:
<debug> (ttyHS3): --> 'AT+CNUM<CR>'
<debug> (ttyHS3): <-- '<CR><LF>+CME ERROR: 14<CR><LF>'
<debug> Got failure code 14: SIM busy
<debug> (ttyHS3) device open count is 1 (close)
<warn> couldn't load list of Own Numbers: 'Failed to parse NV MDN command result: -17'
<debug> (ttyHS3) device open count is 2 (open)
<debug> (ttyHS3): --> 'AT_OPSYS?<CR>'
<debug> (ttyHS3): <-- '<CR><LF>_OPSYS: 1,2<CR><LF><CR><LF>OK<CR><LF>'
<warn> couldn't load current allowed/preferred modes: 'Couldn't parse OPSYS response: '+CME ERROR: 14
_OPSYS: 1,2''
|
|
|
|
The XCASE terminal mode flag because is no longer specified by POSIX
and has no effect on linux. Because of the latter fact we can remove
it. This fixes a compilation error with musl libc.
|
|
b28230411 moved up the self->priv->forced_close = TRUE, which
caused mm_port_serial_close() to just return without actually
closing the port and cleaning up.
Also, cancel the reopen separately from closing the port since
the two operations are actually independent of each other.
|
|
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
|
|
|
|
This patch removes an extra invocation of g_simple_async_result_complete
on the result associated with each command context in the command queue
when mm_port_serial_close clears the queue. It also changes the code to
complete the results in idle, which avoids a nested invocation of
mm_port_serial_close. That could happen if the completion of the result
calls mm_port_serial_close again (e.g. via at_command_context_free,
at_sequence_context_free in mm-base-modem-at.c). The nested invocation
of mm_port_serial_close could create undesirable effects (e.g. the
assertion on open_count > 0 fails in case of a forced close).
|
|
This patch fixes the following type mismatch in MMPortSerial::port_serial_process_command():
mm-port-serial.c:612:21: error: comparison of unsigned expression < 0 is always false [-Werror,-Wtautological-compare]
if (written < 0) {
~~~~~~~ ^ ~
|
|
|
|
|
|
|
|
Allow having 'MMPortSerial' objects for non-tty devices. This will allow us e.g.
handling /dev/cdc-wdm ports speaking the AT protocol.
|