iface-location: allow enabling without SIM

When the modem is in a failed state because of a SIM-related error,
like a missing SIM, or if the modem is SIM-locked, allow the
Location interface to initialize and be enabled anyway.

This allows someone without a SIM to use the GPS, which does not
particularly require a phone subscription. It also allows
someone with a SIM to use the GPS even if the SIM is still
locked.

This patch was reworked, while keeping the original idea, by:
Aleksander Morgado <aleksander@aleksander.es>

Fixes #183
This commit is contained in:
Raphaël Jakse
2023-12-11 12:37:42 +00:00
committed by Aleksander Morgado
parent 224c04065d
commit 63dd4ad263
5 changed files with 108 additions and 132 deletions
-5
View File
@@ -254,11 +254,6 @@ context_free (void)
static void
ensure_modem_location (void)
{
if (mm_modem_get_state (mm_object_peek_modem (ctx->object)) < MM_MODEM_STATE_ENABLED) {
g_printerr ("error: modem not enabled yet\n");
exit (EXIT_FAILURE);
}
if (!ctx->modem_location) {
g_printerr ("error: modem has no location capabilities\n");
exit (EXIT_FAILURE);
+7 -2
View File
@@ -1113,8 +1113,13 @@ typedef enum { /*< underscore_name=mm_sms_cdma_service_category >*/
* @MM_MODEM_LOCATION_SOURCE_GPS_NMEA: GPS location given as NMEA traces.
* @MM_MODEM_LOCATION_SOURCE_CDMA_BS: CDMA base station position.
* @MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED: No location given, just GPS module setup. Since 1.4.
* @MM_MODEM_LOCATION_SOURCE_AGPS_MSA: Mobile Station Assisted A-GPS location requested. Since 1.12.
* @MM_MODEM_LOCATION_SOURCE_AGPS_MSB: Mobile Station Based A-GPS location requested. Since 1.12.
* @MM_MODEM_LOCATION_SOURCE_AGPS_MSA: Mobile Station Assisted A-GPS location requested. In
* MSA A-GPS, the position fix is computed by a server online. The modem must have a valid SIM
* card inserted and be enabled for this mode to be allowed. Since 1.12.
* @MM_MODEM_LOCATION_SOURCE_AGPS_MSB: Mobile Station Based A-GPS location requested. In MSB
* A-GPS, the position fix is computed by the modem, but it first gathers information from an
* online server to facilitate the process (e.g. ephemeris). The modem must have a valid SIM
* card inserted and be enabled for this mode to be allowed. Since 1.12.
*
* Sources of location information supported by the modem.
*
@@ -40,18 +40,14 @@
no GPS sources are requested by the user, the GNSS engine will need
to be stopped explicitly).
This method may require the client to authenticate itself.
When location signaling is enabled by the user, any client application (including
malicious ones!) would be able to use the #org.freedesktop.ModemManager1.Modem.Location:Location
property to receive location updates. If further security is desired, the
@signal_location argument can be set to %FALSE to disable location
updates via D-Bus signals and require applications to call
authenticated APIs (like <link linkend="gdbus-method-org-freedesktop-ModemManager1-Modem-Location.GetLocation">GetLocation()</link>)
to get the location information.
By default location signaling is disabled, and therefore the
#org.freedesktop.ModemManager1.Modem.Location:Location property will not
to get the location information. By default location signaling is disabled,
and therefore the #org.freedesktop.ModemManager1.Modem.Location:Location property will not
be usable until explicitly enabled by the user.
The optional
@@ -62,12 +58,12 @@
<link linkend="MM-MODEM-LOCATION-SOURCE-GPS-RAW:CAPS">MM_MODEM_LOCATION_SOURCE_GPS_RAW</link>
or
<link linkend="MM-MODEM-LOCATION-SOURCE-GPS-NMEA:CAPS">MM_MODEM_LOCATION_SOURCE_GPS_NMEA</link>.
Both A-GPS operation modes rely on having a valid data connection to connect to an online
server, and therefore require the modem to have a valid SIM card and be enabled. If no A-GPS mode
is specified, standalone GPS is assumed.
Both
<link linkend="MM-MODEM-LOCATION-SOURCE-AGPS-MSA:CAPS">MM_MODEM_LOCATION_SOURCE_AGPS_MSA</link>
and
<link linkend="MM-MODEM-LOCATION-SOURCE-AGPS-MSB:CAPS">MM_MODEM_LOCATION_SOURCE_AGPS_MSB</link>
cannot be given at the same time, and if none given, standalone GPS is assumed.
Since 1.24, standalone GPS sources may be enabled even with the modem in failed state, e.g.
when there is no SIM card inserted.
Since: 1.0
-->
@@ -119,9 +115,10 @@
There is no maximum @data size limit specified, default DBus system bus limits apply.
This method may be used when the device does not have a mobile network connection by
itself, and therefore it cannot use any A-GPS server to improve the accuracy of the
position. In this case, the user can instead download the assistance data files using
a WiFi or LAN network, and inject them to the GNSS engine manually.
itself (e.g. when not even a SIM is inserted), and therefore it cannot use any A-GPS
server to improve the accuracy of the position. In this case, the user can instead
download the assistance data files using a WiFi or LAN network, and inject them to
the GNSS engine manually.
Since: 1.10
-->
+12 -12
View File
@@ -12339,13 +12339,13 @@ typedef enum {
INITIALIZE_STEP_IFACE_3GPP_PROFILE_MANAGER,
INITIALIZE_STEP_IFACE_3GPP_USSD,
INITIALIZE_STEP_IFACE_CDMA,
INITIALIZE_STEP_IFACE_LOCATION,
INITIALIZE_STEP_IFACE_MESSAGING,
INITIALIZE_STEP_IFACE_TIME,
INITIALIZE_STEP_IFACE_SIGNAL,
INITIALIZE_STEP_IFACE_OMA,
INITIALIZE_STEP_IFACE_SAR,
INITIALIZE_STEP_FALLBACK_LIMITED,
INITIALIZE_STEP_IFACE_LOCATION,
INITIALIZE_STEP_IFACE_VOICE,
INITIALIZE_STEP_IFACE_FIRMWARE,
INITIALIZE_STEP_IFACE_SIMPLE,
@@ -12637,14 +12637,6 @@ initialize_step (GTask *task)
ctx->step++;
/* fall through */
case INITIALIZE_STEP_IFACE_LOCATION:
/* Initialize the Location interface */
mm_iface_modem_location_initialize (MM_IFACE_MODEM_LOCATION (ctx->self),
g_task_get_cancellable (task),
(GAsyncReadyCallback)iface_modem_location_initialize_ready,
task);
return;
case INITIALIZE_STEP_IFACE_MESSAGING:
/* Initialize the Messaging interface */
mm_iface_modem_messaging_initialize (MM_IFACE_MODEM_MESSAGING (ctx->self),
@@ -12691,6 +12683,14 @@ initialize_step (GTask *task)
ctx->step++;
/* fall through */
case INITIALIZE_STEP_IFACE_LOCATION:
/* Initialize the Location interface */
mm_iface_modem_location_initialize (MM_IFACE_MODEM_LOCATION (ctx->self),
g_task_get_cancellable (task),
(GAsyncReadyCallback)iface_modem_location_initialize_ready,
task);
return;
case INITIALIZE_STEP_IFACE_VOICE:
/* Initialize the Voice interface */
mm_iface_modem_voice_initialize (MM_IFACE_MODEM_VOICE (ctx->self),
@@ -12731,16 +12731,16 @@ initialize_step (GTask *task)
"Modem in failed state: %s",
mm_modem_state_failed_reason_get_string (reason));
/* Ensure we only leave the Modem, Voice and Firmware interfaces
/* Ensure we only leave the Modem, Voice, Location and Firmware interfaces
* around. A failure could be caused by firmware issues, which
* a firmware update, switch, or provisioning could fix. We also
* leave the Voice interface around so that we can attempt
* emergency voice calls.
* emergency voice calls, and the Location interface so that we can use
* GNSS without a SIM card
*/
mm_iface_modem_3gpp_profile_manager_shutdown (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (ctx->self));
mm_iface_modem_3gpp_ussd_shutdown (MM_IFACE_MODEM_3GPP_USSD (ctx->self));
mm_iface_modem_cdma_shutdown (MM_IFACE_MODEM_CDMA (ctx->self));
mm_iface_modem_location_shutdown (MM_IFACE_MODEM_LOCATION (ctx->self));
mm_iface_modem_signal_shutdown (MM_IFACE_MODEM_SIGNAL (ctx->self));
mm_iface_modem_messaging_shutdown (MM_IFACE_MODEM_MESSAGING (ctx->self));
mm_iface_modem_time_shutdown (MM_IFACE_MODEM_TIME (ctx->self));
+78 -99
View File
@@ -890,11 +890,11 @@ setup_gathering (MMIfaceModemLocation *self,
/*****************************************************************************/
typedef struct {
MmGdbusModemLocation *skeleton;
MmGdbusModemLocation *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModemLocation *self;
guint32 sources;
gboolean signal_location;
MMIfaceModemLocation *self;
guint32 sources;
gboolean signal_location;
} HandleSetupContext;
static void
@@ -903,13 +903,13 @@ handle_setup_context_free (HandleSetupContext *ctx)
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
g_free (ctx);
g_slice_free (HandleSetupContext, ctx);
}
static void
setup_gathering_ready (MMIfaceModemLocation *self,
GAsyncResult *res,
HandleSetupContext *ctx)
GAsyncResult *res,
HandleSetupContext *ctx)
{
GError *error = NULL;
@@ -922,15 +922,16 @@ setup_gathering_ready (MMIfaceModemLocation *self,
}
static void
handle_setup_auth_ready (MMBaseModem *self,
GAsyncResult *res,
handle_setup_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleSetupContext *ctx)
{
GError *error = NULL;
MMModemState modem_state;
MMModemLocationSource not_supported;
LocationContext *location_ctx;
gchar *str;
GError *error = NULL;
MMModemState modem_state;
MMModemLocationSource not_supported;
MMModemLocationSource require_enabled;
LocationContext *location_ctx;
g_autofree gchar *str = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -938,17 +939,6 @@ handle_setup_auth_ready (MMBaseModem *self,
return;
}
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
if (modem_state < MM_MODEM_STATE_ENABLED) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
"Cannot setup location: device not yet enabled");
handle_setup_context_free (ctx);
return;
}
/* If any of the location sources being enabled is NOT supported, set error */
not_supported = ((mm_gdbus_modem_location_get_capabilities (ctx->skeleton) ^ ctx->sources) & ctx->sources);
if (not_supported != MM_MODEM_LOCATION_SOURCE_NONE) {
@@ -956,7 +946,26 @@ handle_setup_auth_ready (MMBaseModem *self,
mm_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot enable unsupported location sources: '%s'", str);
handle_setup_context_free (ctx);
g_free (str);
return;
}
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
/* Location sources that require any kind of network access may be
* enabled only when the modem is enabled. Generic standalone GPS may be
* enabled even without a SIM card */
require_enabled = ctx->sources & (MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI |
MM_MODEM_LOCATION_SOURCE_CDMA_BS |
MM_MODEM_LOCATION_SOURCE_AGPS_MSA |
MM_MODEM_LOCATION_SOURCE_AGPS_MSB);
if (require_enabled && (modem_state < MM_MODEM_STATE_ENABLED)) {
str = mm_modem_location_source_build_string_from_mask (require_enabled);
mm_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
"Cannot enable location '%s': device not yet enabled", str);
handle_setup_context_free (ctx);
return;
}
@@ -983,7 +992,6 @@ handle_setup_auth_ready (MMBaseModem *self,
str = mm_modem_location_source_build_string_from_mask (ctx->sources);
mm_obj_dbg (self, "setting up location sources: '%s'", str);
g_free (str);
/* Go on to enable or disable the requested sources */
setup_gathering (ctx->self,
@@ -993,15 +1001,15 @@ handle_setup_auth_ready (MMBaseModem *self,
}
static gboolean
handle_setup (MmGdbusModemLocation *skeleton,
handle_setup (MmGdbusModemLocation *skeleton,
GDBusMethodInvocation *invocation,
guint32 sources,
gboolean signal_location,
MMIfaceModemLocation *self)
guint32 sources,
gboolean signal_location,
MMIfaceModemLocation *self)
{
HandleSetupContext *ctx;
ctx = g_new (HandleSetupContext, 1);
ctx = g_slice_new0 (HandleSetupContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
@@ -1019,10 +1027,10 @@ handle_setup (MmGdbusModemLocation *skeleton,
/*****************************************************************************/
typedef struct {
MmGdbusModemLocation *skeleton;
MmGdbusModemLocation *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModemLocation *self;
gchar *supl;
MMIfaceModemLocation *self;
gchar *supl;
} HandleSetSuplServerContext;
static void
@@ -1036,8 +1044,8 @@ handle_set_supl_server_context_free (HandleSetSuplServerContext *ctx)
}
static void
set_supl_server_ready (MMIfaceModemLocation *self,
GAsyncResult *res,
set_supl_server_ready (MMIfaceModemLocation *self,
GAsyncResult *res,
HandleSetSuplServerContext *ctx)
{
GError *error = NULL;
@@ -1053,12 +1061,11 @@ set_supl_server_ready (MMIfaceModemLocation *self,
}
static void
handle_set_supl_server_auth_ready (MMBaseModem *self,
GAsyncResult *res,
handle_set_supl_server_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleSetSuplServerContext *ctx)
{
GError *error = NULL;
MMModemState modem_state;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1066,17 +1073,6 @@ handle_set_supl_server_auth_ready (MMBaseModem *self,
return;
}
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
if (modem_state < MM_MODEM_STATE_ENABLED) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
"Cannot set SUPL server: device not yet enabled");
handle_set_supl_server_context_free (ctx);
return;
}
/* If A-GPS is NOT supported, set error */
if (!(mm_gdbus_modem_location_get_capabilities (ctx->skeleton) & (MM_MODEM_LOCATION_SOURCE_AGPS_MSA | MM_MODEM_LOCATION_SOURCE_AGPS_MSB))) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
@@ -1109,14 +1105,14 @@ handle_set_supl_server_auth_ready (MMBaseModem *self,
}
static gboolean
handle_set_supl_server (MmGdbusModemLocation *skeleton,
handle_set_supl_server (MmGdbusModemLocation *skeleton,
GDBusMethodInvocation *invocation,
const gchar *supl,
MMIfaceModemLocation *self)
const gchar *supl,
MMIfaceModemLocation *self)
{
HandleSetSuplServerContext *ctx;
ctx = g_slice_new (HandleSetSuplServerContext);
ctx = g_slice_new0 (HandleSetSuplServerContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
@@ -1160,7 +1156,6 @@ inject_assistance_data_ready (MMIfaceModemLocation *self,
mm_dbus_method_invocation_take_error (ctx->invocation, error);
else
mm_gdbus_modem_location_complete_inject_assistance_data (ctx->skeleton, ctx->invocation);
handle_inject_assistance_data_context_free (ctx);
}
@@ -1214,7 +1209,7 @@ handle_inject_assistance_data (MmGdbusModemLocation *skeleton,
{
HandleInjectAssistanceDataContext *ctx;
ctx = g_slice_new (HandleInjectAssistanceDataContext);
ctx = g_slice_new0 (HandleInjectAssistanceDataContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
@@ -1231,9 +1226,9 @@ handle_inject_assistance_data (MmGdbusModemLocation *skeleton,
/*****************************************************************************/
typedef struct {
MmGdbusModemLocation *skeleton;
MmGdbusModemLocation *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModemLocation *self;
MMIfaceModemLocation *self;
guint rate;
} HandleSetGpsRefreshRateContext;
@@ -1247,12 +1242,11 @@ handle_set_gps_refresh_rate_context_free (HandleSetGpsRefreshRateContext *ctx)
}
static void
handle_set_gps_refresh_rate_auth_ready (MMBaseModem *self,
GAsyncResult *res,
handle_set_gps_refresh_rate_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleSetGpsRefreshRateContext *ctx)
{
GError *error = NULL;
MMModemState modem_state;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1260,17 +1254,6 @@ handle_set_gps_refresh_rate_auth_ready (MMBaseModem *self,
return;
}
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
if (modem_state < MM_MODEM_STATE_ENABLED) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
"Cannot set SUPL server: device not yet enabled");
handle_set_gps_refresh_rate_context_free (ctx);
return;
}
/* If GPS is NOT supported, set error */
if (!(mm_gdbus_modem_location_get_capabilities (ctx->skeleton) & ((MM_MODEM_LOCATION_SOURCE_GPS_RAW |
MM_MODEM_LOCATION_SOURCE_GPS_NMEA)))) {
@@ -1287,14 +1270,14 @@ handle_set_gps_refresh_rate_auth_ready (MMBaseModem *self,
}
static gboolean
handle_set_gps_refresh_rate (MmGdbusModemLocation *skeleton,
handle_set_gps_refresh_rate (MmGdbusModemLocation *skeleton,
GDBusMethodInvocation *invocation,
guint rate,
MMIfaceModemLocation *self)
guint rate,
MMIfaceModemLocation *self)
{
HandleSetGpsRefreshRateContext *ctx;
ctx = g_slice_new (HandleSetGpsRefreshRateContext);
ctx = g_slice_new0 (HandleSetGpsRefreshRateContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
@@ -1311,9 +1294,9 @@ handle_set_gps_refresh_rate (MmGdbusModemLocation *skeleton,
/*****************************************************************************/
typedef struct {
MmGdbusModemLocation *skeleton;
MmGdbusModemLocation *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModemLocation *self;
MMIfaceModemLocation *self;
} HandleGetLocationContext;
static void
@@ -1322,17 +1305,16 @@ handle_get_location_context_free (HandleGetLocationContext *ctx)
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
g_free (ctx);
g_slice_free (HandleGetLocationContext, ctx);
}
static void
handle_get_location_auth_ready (MMBaseModem *self,
GAsyncResult *res,
handle_get_location_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleGetLocationContext *ctx)
{
MMModemState modem_state;
LocationContext *location_ctx;
GError *error = NULL;
GError *error = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1340,17 +1322,6 @@ handle_get_location_auth_ready (MMBaseModem *self,
return;
}
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
if (modem_state < MM_MODEM_STATE_ENABLED) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
"Cannot get location: device not yet enabled");
handle_get_location_context_free (ctx);
return;
}
location_ctx = get_location_context (ctx->self);
mm_gdbus_modem_location_complete_get_location (
ctx->skeleton,
@@ -1364,13 +1335,13 @@ handle_get_location_auth_ready (MMBaseModem *self,
}
static gboolean
handle_get_location (MmGdbusModemLocation *skeleton,
handle_get_location (MmGdbusModemLocation *skeleton,
GDBusMethodInvocation *invocation,
MMIfaceModemLocation *self)
MMIfaceModemLocation *self)
{
HandleGetLocationContext *ctx;
ctx = g_new (HandleGetLocationContext, 1);
ctx = g_slice_new0 (HandleGetLocationContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
@@ -1450,6 +1421,10 @@ interface_disabling_step (GTask *task)
/* fall through */
case DISABLING_STEP_DISABLE_GATHERING:
/* We disable all sources here. It is true that the user may have enabled GPS
* early before getting the modem enabled, and that we may have left it active
* once the modem transitions to enabled state, but for the disabling phase
* we reset everything. */
setup_gathering (self,
MM_MODEM_LOCATION_SOURCE_NONE,
(GAsyncReadyCallback)disabling_location_gathering_ready,
@@ -1573,6 +1548,7 @@ interface_enabling_step (GTask *task)
case ENABLING_STEP_ENABLE_GATHERING: {
MMModemLocationSource default_sources;
MMModemLocationSource currently_enabled;
/* By default, we'll enable all NON-GPS sources */
default_sources = mm_gdbus_modem_location_get_capabilities (ctx->skeleton);
@@ -1582,8 +1558,11 @@ interface_enabling_step (GTask *task)
MM_MODEM_LOCATION_SOURCE_AGPS_MSA |
MM_MODEM_LOCATION_SOURCE_AGPS_MSB);
/* If standalone GPS was already enabled, we keep it enabled */
currently_enabled = mm_gdbus_modem_location_get_enabled (ctx->skeleton);
setup_gathering (self,
default_sources,
default_sources | currently_enabled,
(GAsyncReadyCallback)enabling_location_gathering_ready,
task);
return;