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:
@@ -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 */
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
Reference in New Issue
Block a user