core,qmi: don't assume QMI port is always available

When the modem gets unplugged all ports disappear from the modem, so don't
assume the port is always given.

E.g. if the unplug happens in the middle of the initialization sequence we may
end up with nasty segfaults:

    Crash reason:  SIGSEGV
    Crash address: 0x0

    Thread 0 (crashed)
     0  ModemManager!mm_qmi_port_peek_client [mm-qmi-port.c : 50 + 0x0]
        rbx = 0x00007fbb5c1d8010   r12 = 0x0000000000000003
        r13 = 0x00007fbb5c1f9880   r14 = 0x00007fbb59a30980
        r15 = 0x00007fbb5c187a60   rip = 0x00007fbb5a1a54c0
        rsp = 0x00007fffc6c0f628   rbp = 0x00007fffc6c0f650
        Found by: given as instruction pointer in context
     1  ModemManager!peek_qmi_client [mm-broadband-modem-qmi.c : 109 + 0x24]
        rbx = 0x00007fbb5c1d8010   r12 = 0x0000000000000003
        r13 = 0x00007fbb5c1f9880   r14 = 0x00007fbb59a30980
        r15 = 0x00007fbb5c187a60   rip = 0x00007fbb5a193851
        rsp = 0x00007fffc6c0f630   rbp = 0x00007fffc6c0f650
        Found by: call frame info
     2  ModemManager!ensure_qmi_client [mm-broadband-modem-qmi.c : 132 + 0x4]
        rbx = 0x00007fbb5c1d8010   r12 = 0x00007fbb5a165140
        r13 = 0x00007fbb5c1f9880   r14 = 0x00007fbb59a30980
        r15 = 0x00007fbb5c187a60   rip = 0x00007fbb5a1938e4
        rsp = 0x00007fffc6c0f650   rbp = 0x00007fffc6c0f690
        Found by: call frame info
    ...

Reported by: Ben Chan <benchan@chromium.org>
This commit is contained in:
Aleksander Morgado
2012-10-11 09:23:49 +02:00
parent ba64c49f36
commit 014d0688ff
3 changed files with 76 additions and 21 deletions

View File

@@ -104,9 +104,19 @@ peek_qmi_client (MMBroadbandModemQmi *self,
QmiService service, QmiService service,
GError **error) GError **error)
{ {
MMQmiPort *port;
QmiClient *client; QmiClient *client;
client = mm_qmi_port_peek_client (mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self)), port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
if (!port) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Couldn't peek QMI port");
return NULL;
}
client = mm_qmi_port_peek_client (port,
service, service,
MM_QMI_PORT_FLAG_DEFAULT); MM_QMI_PORT_FLAG_DEFAULT);
if (!client) if (!client)
@@ -4941,16 +4951,21 @@ messaging_check_support (MMIfaceModemMessaging *self,
{ {
GSimpleAsyncResult *result; GSimpleAsyncResult *result;
gboolean supported; gboolean supported;
MMQmiPort *port;
result = g_simple_async_result_new (G_OBJECT (self), result = g_simple_async_result_new (G_OBJECT (self),
callback, callback,
user_data, user_data,
messaging_check_support); messaging_check_support);
/* If we have support for the WMS client, messaging is supported */ port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
supported = !!mm_qmi_port_peek_client (mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self)), if (!port)
QMI_SERVICE_WMS, supported = FALSE;
MM_QMI_PORT_FLAG_DEFAULT); else
/* If we have support for the WMS client, messaging is supported */
supported = !!mm_qmi_port_peek_client (port,
QMI_SERVICE_WMS,
MM_QMI_PORT_FLAG_DEFAULT);
/* We only handle 3GPP messaging (PDU based) currently, so just ignore /* We only handle 3GPP messaging (PDU based) currently, so just ignore
* CDMA-only QMI modems */ * CDMA-only QMI modems */
@@ -5673,6 +5688,7 @@ parent_load_capabilities_ready (MMIfaceModemLocation *self,
{ {
MMModemLocationSource sources; MMModemLocationSource sources;
GError *error = NULL; GError *error = NULL;
MMQmiPort *port;
sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error); sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
if (error) { if (error) {
@@ -5682,11 +5698,13 @@ parent_load_capabilities_ready (MMIfaceModemLocation *self,
return; return;
} }
port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
/* Now our own check. /* Now our own check.
* If we have support for the PDS client, GPS location is supported */ * If we have support for the PDS client, GPS location is supported */
if (mm_qmi_port_peek_client (mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self)), if (port && mm_qmi_port_peek_client (port,
QMI_SERVICE_PDS, QMI_SERVICE_PDS,
MM_QMI_PORT_FLAG_DEFAULT)) MM_QMI_PORT_FLAG_DEFAULT))
sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW); sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW);
/* So we're done, complete */ /* So we're done, complete */
@@ -6931,7 +6949,16 @@ initialization_started (MMBroadbandModem *self,
user_data, user_data,
initialization_started); initialization_started);
ctx->qmi = mm_base_modem_get_port_qmi (MM_BASE_MODEM (self)); ctx->qmi = mm_base_modem_get_port_qmi (MM_BASE_MODEM (self));
g_assert (ctx->qmi);
/* This may happen if we unplug the modem unexpectedly */
if (!ctx->qmi) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Cannot initialize: QMI port went missing");
initialization_started_context_complete_and_free (ctx);
return;
}
if (mm_qmi_port_is_open (ctx->qmi)) { if (mm_qmi_port_is_open (ctx->qmi)) {
/* Nothing to be done, just launch parent's callback */ /* Nothing to be done, just launch parent's callback */

View File

@@ -40,16 +40,30 @@ ensure_qmi_client (MMSimQmi *self,
{ {
MMBaseModem *modem = NULL; MMBaseModem *modem = NULL;
QmiClient *client; QmiClient *client;
MMQmiPort *port;
g_object_get (self, g_object_get (self,
MM_SIM_MODEM, &modem, MM_SIM_MODEM, &modem,
NULL); NULL);
g_assert (MM_IS_BASE_MODEM (modem)); g_assert (MM_IS_BASE_MODEM (modem));
client = mm_qmi_port_peek_client (mm_base_modem_peek_port_qmi (modem), port = mm_base_modem_peek_port_qmi (modem);
g_object_unref (modem);
if (!port) {
g_simple_async_report_error_in_idle (G_OBJECT (self),
callback,
user_data,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Couldn't peek QMI port");
return FALSE;
}
client = mm_qmi_port_peek_client (port,
service, service,
MM_QMI_PORT_FLAG_DEFAULT); MM_QMI_PORT_FLAG_DEFAULT);
if (!client) if (!client) {
g_simple_async_report_error_in_idle (G_OBJECT (self), g_simple_async_report_error_in_idle (G_OBJECT (self),
callback, callback,
user_data, user_data,
@@ -57,11 +71,11 @@ ensure_qmi_client (MMSimQmi *self,
MM_CORE_ERROR_FAILED, MM_CORE_ERROR_FAILED,
"Couldn't peek client for service '%s'", "Couldn't peek client for service '%s'",
qmi_service_get_string (service)); qmi_service_get_string (service));
else return FALSE;
*o_client = client; }
g_object_unref (modem); *o_client = client;
return !!client; return TRUE;
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@@ -43,16 +43,30 @@ ensure_qmi_client (MMSmsQmi *self,
{ {
MMBaseModem *modem = NULL; MMBaseModem *modem = NULL;
QmiClient *client; QmiClient *client;
MMQmiPort *port;
g_object_get (self, g_object_get (self,
MM_SMS_MODEM, &modem, MM_SMS_MODEM, &modem,
NULL); NULL);
g_assert (MM_IS_BASE_MODEM (modem)); g_assert (MM_IS_BASE_MODEM (modem));
client = mm_qmi_port_peek_client (mm_base_modem_peek_port_qmi (modem), port = mm_base_modem_peek_port_qmi (modem);
g_object_unref (modem);
if (!port) {
g_simple_async_report_error_in_idle (G_OBJECT (self),
callback,
user_data,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Couldn't peek QMI port");
return FALSE;
}
client = mm_qmi_port_peek_client (port,
service, service,
MM_QMI_PORT_FLAG_DEFAULT); MM_QMI_PORT_FLAG_DEFAULT);
if (!client) if (!client) {
g_simple_async_report_error_in_idle (G_OBJECT (self), g_simple_async_report_error_in_idle (G_OBJECT (self),
callback, callback,
user_data, user_data,
@@ -60,11 +74,11 @@ ensure_qmi_client (MMSmsQmi *self,
MM_CORE_ERROR_FAILED, MM_CORE_ERROR_FAILED,
"Couldn't peek client for service '%s'", "Couldn't peek client for service '%s'",
qmi_service_get_string (service)); qmi_service_get_string (service));
else return FALSE;
*o_client = client; }
g_object_unref (modem); *o_client = client;
return !!client; return TRUE;
} }
/*****************************************************************************/ /*****************************************************************************/