diff options
-rw-r--r-- | docs/reference/libmm-glib/libmm-glib-sections.txt | 4 | ||||
-rw-r--r-- | libmm-glib/mm-location-3gpp.c | 284 | ||||
-rw-r--r-- | libmm-glib/mm-location-3gpp.h | 35 | ||||
-rw-r--r-- | src/mm-iface-modem-3gpp.c | 12 | ||||
-rw-r--r-- | src/mm-iface-modem-location.c | 19 | ||||
-rw-r--r-- | src/mm-iface-modem-location.h | 5 |
6 files changed, 204 insertions, 155 deletions
diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt index 46a10bba..670d42c7 100644 --- a/docs/reference/libmm-glib/libmm-glib-sections.txt +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt @@ -509,6 +509,7 @@ MMLocation3gpp <SUBSECTION Getters> mm_location_3gpp_get_mobile_country_code mm_location_3gpp_get_mobile_network_code +mm_location_3gpp_get_operator_code mm_location_3gpp_get_location_area_code mm_location_3gpp_get_tracking_area_code mm_location_3gpp_get_cell_id @@ -519,8 +520,7 @@ mm_location_3gpp_new_from_string_variant mm_location_3gpp_set_cell_id mm_location_3gpp_set_location_area_code mm_location_3gpp_set_tracking_area_code -mm_location_3gpp_set_mobile_country_code -mm_location_3gpp_set_mobile_network_code +mm_location_3gpp_set_operator_code mm_location_3gpp_reset <SUBSECTION Standard> MMLocation3gppClass diff --git a/libmm-glib/mm-location-3gpp.c b/libmm-glib/mm-location-3gpp.c index c23aeec5..92e20f11 100644 --- a/libmm-glib/mm-location-3gpp.c +++ b/libmm-glib/mm-location-3gpp.c @@ -37,20 +37,85 @@ G_DEFINE_TYPE (MMLocation3gpp, mm_location_3gpp, G_TYPE_OBJECT); struct _MMLocation3gppPrivate { - guint mobile_country_code; - guint mobile_network_code; + gchar *operator_code; gulong location_area_code; gulong cell_id; gulong tracking_area_code; - - /* We use 0 as default MNC when unknown, and that is a bit problematic if - * the network operator has actually a 0 MNC (e.g. China Mobile, 46000). - * We need to explicitly track whether MNC is set or not. */ - gboolean mobile_network_code_set; }; /*****************************************************************************/ +static gboolean +validate_string_length (const gchar *display, + const gchar *str, + guint min_length, + guint max_length, + GError **error) +{ + /* Avoid empty strings */ + if (!str || !str[0]) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Invalid %s: none given", + display); + return FALSE; + } + + /* Check min length of the field */ + if (strlen (str) < min_length) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Invalid %s: shorter than the maximum expected (%u): '%s'", + display, + min_length, + str); + return FALSE; + } + + /* Check max length of the field */ + if (strlen (str) > max_length) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Invalid %s: longer than the maximum expected (%u): '%s'", + display, + max_length, + str); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_numeric_string_content (const gchar *display, + const gchar *str, + gboolean hex, + GError **error) +{ + guint i; + + for (i = 0; str[i]; i++) { + if ((hex && !g_ascii_isxdigit (str[i])) || + (!hex && !g_ascii_isdigit (str[i]))) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Invalid %s: unexpected char (%c): '%s'", + display, + str[i], + str); + return FALSE; + } + } + + return TRUE; +} + +/*****************************************************************************/ + /** * mm_location_3gpp_get_mobile_country_code: * @self: a #MMLocation3gpp. @@ -64,30 +129,21 @@ struct _MMLocation3gppPrivate { guint mm_location_3gpp_get_mobile_country_code (MMLocation3gpp *self) { - g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0); + gchar mcc[4]; - return self->priv->mobile_country_code; -} - -/** - * mm_location_3gpp_set_mobile_country_code: (skip) - */ -gboolean -mm_location_3gpp_set_mobile_country_code (MMLocation3gpp *self, - guint mobile_country_code) -{ - g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE); - - /* If no change in the location info, don't do anything */ - if (self->priv->mobile_country_code == mobile_country_code) - return FALSE; + g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0); - self->priv->mobile_country_code = mobile_country_code; - return TRUE; + if (!self->priv->operator_code) + return 0; + memcpy (mcc, self->priv->operator_code, 3); + mcc[4] = '\0'; + return strtol (mcc, NULL, 10); } /*****************************************************************************/ +#ifndef MM_DISABLE_DEPRECATED + /** * mm_location_3gpp_get_mobile_network_code: * @self: a #MMLocation3gpp. @@ -101,32 +157,21 @@ mm_location_3gpp_set_mobile_country_code (MMLocation3gpp *self, * Returns: the MNC, or 0 if unknown. * * Since: 1.0 + * Deprecated: 1.18.0. This function can not separate between two-digit MNCs + * and three-digit MNCs with a leading zero. Use mm_location_3gpp_get_operator_code() + * instead. */ guint mm_location_3gpp_get_mobile_network_code (MMLocation3gpp *self) { g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0); - return self->priv->mobile_network_code; + if (!self->priv->operator_code) + return 0; + return strtol (self->priv->operator_code + 3, NULL, 10); } -/** - * mm_location_3gpp_set_mobile_network_code: (skip) - */ -gboolean -mm_location_3gpp_set_mobile_network_code (MMLocation3gpp *self, - guint mobile_network_code) -{ - g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE); - - /* If no change in the location info, don't do anything */ - if (self->priv->mobile_network_code_set && (self->priv->mobile_network_code == mobile_network_code)) - return FALSE; - - self->priv->mobile_network_code_set = TRUE; - self->priv->mobile_network_code = mobile_network_code; - return TRUE; -} +#endif /* MM_DISABLE_DEPRECATED */ /*****************************************************************************/ @@ -242,6 +287,55 @@ mm_location_3gpp_set_tracking_area_code (MMLocation3gpp *self, /*****************************************************************************/ /** + * mm_location_3gpp_get_operator_code: + * @self: A #MMLocation3gpp. + * + * Gets the 3GPP network Mobile Country Code and Mobile Network Code. + * + * Returned in the format <literal>"MCCMNC"</literal>, where + * <literal>MCC</literal> is the three-digit ITU E.212 Mobile Country Code + * and <literal>MNC</literal> is the two- or three-digit GSM Mobile Network + * Code. e.g. e<literal>"31026"</literal> or <literal>"310260"</literal>. + * + * Returns: (transfer none): The operator code, or %NULL if none available. + * + * Since: 1.18 + */ +const gchar * +mm_location_3gpp_get_operator_code (MMLocation3gpp *self) +{ + g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), NULL); + + return self->priv->operator_code; +} + +/** + * mm_location_3gpp_set_operator_code: (skip) + */ +gboolean +mm_location_3gpp_set_operator_code (MMLocation3gpp *self, + const gchar *operator_code) +{ + g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE); + + /* If no change in operator code, don't do anything */ + if (!g_strcmp0 (operator_code, self->priv->operator_code)) + return FALSE; + + /* Check the validity here, all other functions expect it's valid. */ + if (operator_code && + (!validate_string_length ("MCCMNC", operator_code, 5, 6, NULL) || + !validate_numeric_string_content ("MCCMNC", operator_code, FALSE, NULL))) + return FALSE; + + g_free (self->priv->operator_code); + self->priv->operator_code = g_strdup (operator_code); + return TRUE; +} + +/*****************************************************************************/ + +/** * mm_location_3gpp_reset: (skip) */ gboolean @@ -249,17 +343,14 @@ mm_location_3gpp_reset (MMLocation3gpp *self) { g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE); - if (self->priv->mobile_country_code == 0 && - !self->priv->mobile_network_code_set && - self->priv->mobile_network_code == 0 && + if (self->priv->operator_code == NULL && self->priv->location_area_code == 0 && self->priv->tracking_area_code == 0 && self->priv->cell_id == 0) return FALSE; - self->priv->mobile_country_code = 0; - self->priv->mobile_network_code_set = FALSE; - self->priv->mobile_network_code = 0; + g_free (self->priv->operator_code); + self->priv->operator_code = NULL; self->priv->location_area_code = 0; self->priv->tracking_area_code = 0; self->priv->cell_id = 0; @@ -278,15 +369,14 @@ mm_location_3gpp_get_string_variant (MMLocation3gpp *self) g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), NULL); - if (self->priv->mobile_country_code && - self->priv->mobile_network_code_set && /* MNC 0 is actually valid! */ + if (self->priv->operator_code && (self->priv->location_area_code || self->priv->tracking_area_code) && self->priv->cell_id) { gchar *str; - str = g_strdup_printf ("%u,%u,%lX,%lX,%lX", - self->priv->mobile_country_code, - self->priv->mobile_network_code, + str = g_strdup_printf ("%.3s,%s,%lX,%lX,%lX", + self->priv->operator_code, + self->priv->operator_code + 3, self->priv->location_area_code, self->priv->cell_id, self->priv->tracking_area_code); @@ -300,62 +390,6 @@ mm_location_3gpp_get_string_variant (MMLocation3gpp *self) /*****************************************************************************/ -static gboolean -validate_string_length (const gchar *display, - const gchar *str, - guint max_length, - GError **error) -{ - /* Avoid empty strings */ - if (!str || !str[0]) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_INVALID_ARGS, - "Invalid %s: none given", - display); - return FALSE; - } - - /* Check max length of the field */ - if (strlen (str) > max_length) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_INVALID_ARGS, - "Invalid %s: longer than the maximum expected (%u): '%s'", - display, - max_length, - str); - return FALSE; - } - - return TRUE; -} - -static gboolean -validate_numeric_string_content (const gchar *display, - const gchar *str, - gboolean hex, - GError **error) -{ - guint i; - - for (i = 0; str[i]; i++) { - if ((hex && !g_ascii_isxdigit (str[i])) || - (!hex && !g_ascii_isdigit (str[i]))) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_INVALID_ARGS, - "Invalid %s: unexpected char (%c): '%s'", - display, - str[i], - str); - return FALSE; - } - } - - return TRUE; -} - /** * mm_location_3gpp_new_from_string_variant: (skip) */ @@ -386,20 +420,24 @@ mm_location_3gpp_new_from_string_variant (GVariant *string, } /* Validate fields */ - if (validate_string_length ("MCC", split[0], 3, error) && + if (validate_string_length ("MCC", split[0], 0, 3, error) && validate_numeric_string_content ("MCC", split[0], FALSE, error) && - validate_string_length ("MNC", split[1], 3, error) && + validate_string_length ("MNC", split[1], 0, 3, error) && validate_numeric_string_content ("MNC", split[1], FALSE, error) && - validate_string_length ("Location area code", split[2], 4, error) && + validate_string_length ("Location area code", split[2], 0, 4, error) && validate_numeric_string_content ("Location area code", split[2], TRUE, error) && - validate_string_length ("Cell ID", split[3], 8, error) && + validate_string_length ("Cell ID", split[3], 0, 8, error) && validate_numeric_string_content ("Cell ID", split[3], TRUE, error) && - validate_string_length ("Tracking area code", split[4], 8, error) && + validate_string_length ("Tracking area code", split[4], 0, 8, error) && validate_numeric_string_content ("Tracking area code", split[4], TRUE, error)) { + gchar *operator_code; /* Create new location object */ self = mm_location_3gpp_new (); - self->priv->mobile_country_code = strtol (split[0], NULL, 10); - self->priv->mobile_network_code = strtol (split[1], NULL, 10); + /* Join MCC and MNC and ensure they are zero-padded to required widths */ + self->priv->operator_code = g_strdup_printf ("%03lu%0*lu", + strtoul (split[0], NULL, 10), + strlen (split[1]) == 3 ? 3 : 2, + strtoul (split[1], NULL, 10)); self->priv->location_area_code = strtol (split[2], NULL, 16); self->priv->cell_id = strtol (split[3], NULL, 16); self->priv->tracking_area_code = strtol (split[4], NULL, 16); @@ -430,9 +468,21 @@ mm_location_3gpp_init (MMLocation3gpp *self) } static void +finalize (GObject *object) +{ + MMLocation3gpp *self = MM_LOCATION_3GPP (object); + + g_free (self->priv->operator_code); + + G_OBJECT_CLASS (mm_location_3gpp_parent_class)->finalize (object); +} + +static void mm_location_3gpp_class_init (MMLocation3gppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (object_class, sizeof (MMLocation3gppPrivate)); + + object_class->finalize = finalize; } diff --git a/libmm-glib/mm-location-3gpp.h b/libmm-glib/mm-location-3gpp.h index bac7a39f..5f078234 100644 --- a/libmm-glib/mm-location-3gpp.h +++ b/libmm-glib/mm-location-3gpp.h @@ -56,11 +56,16 @@ struct _MMLocation3gppClass { GType mm_location_3gpp_get_type (void); G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMLocation3gpp, g_object_unref) -guint mm_location_3gpp_get_mobile_country_code (MMLocation3gpp *self); -guint mm_location_3gpp_get_mobile_network_code (MMLocation3gpp *self); -gulong mm_location_3gpp_get_location_area_code (MMLocation3gpp *self); -gulong mm_location_3gpp_get_cell_id (MMLocation3gpp *self); -gulong mm_location_3gpp_get_tracking_area_code (MMLocation3gpp *self); +guint mm_location_3gpp_get_mobile_country_code (MMLocation3gpp *self); +gulong mm_location_3gpp_get_location_area_code (MMLocation3gpp *self); +gulong mm_location_3gpp_get_cell_id (MMLocation3gpp *self); +gulong mm_location_3gpp_get_tracking_area_code (MMLocation3gpp *self); +const gchar *mm_location_3gpp_get_operator_code (MMLocation3gpp *self); + +#ifndef MM_DISABLE_DEPRECATED +G_DEPRECATED +guint mm_location_3gpp_get_mobile_network_code (MMLocation3gpp *self); +#endif /*****************************************************************************/ /* ModemManager/libmm-glib/mmcli specific methods */ @@ -75,17 +80,15 @@ MMLocation3gpp *mm_location_3gpp_new (void); MMLocation3gpp *mm_location_3gpp_new_from_string_variant (GVariant *string, GError **error); -gboolean mm_location_3gpp_set_mobile_country_code (MMLocation3gpp *self, - guint mobile_country_code); -gboolean mm_location_3gpp_set_mobile_network_code (MMLocation3gpp *self, - guint mobile_network_code); -gboolean mm_location_3gpp_set_location_area_code (MMLocation3gpp *self, - gulong location_area_code); -gboolean mm_location_3gpp_set_cell_id (MMLocation3gpp *self, - gulong cell_id); -gboolean mm_location_3gpp_set_tracking_area_code (MMLocation3gpp *self, - gulong tracking_area_code); -gboolean mm_location_3gpp_reset (MMLocation3gpp *self); +gboolean mm_location_3gpp_set_operator_code (MMLocation3gpp *self, + const gchar *operator_code); +gboolean mm_location_3gpp_set_location_area_code (MMLocation3gpp *self, + gulong location_area_code); +gboolean mm_location_3gpp_set_cell_id (MMLocation3gpp *self, + gulong cell_id); +gboolean mm_location_3gpp_set_tracking_area_code (MMLocation3gpp *self, + gulong tracking_area_code); +gboolean mm_location_3gpp_reset (MMLocation3gpp *self); #endif diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c index 0b07534f..ff5999d3 100644 --- a/src/mm-iface-modem-3gpp.c +++ b/src/mm-iface-modem-3gpp.c @@ -1424,15 +1424,13 @@ load_operator_code_ready (MMIfaceModem3gpp *self, ReloadCurrentRegistrationInfoContext *ctx; GError *error = NULL; gchar *str; - guint16 mcc = 0; - guint16 mnc = 0; ctx = g_task_get_task_data (task); str = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_operator_code_finish (self, res, &error); if (error) { mm_obj_warn (self, "couldn't load operator code: %s", error->message); - } else if (!mm_3gpp_parse_operator_id (str, &mcc, &mnc, NULL, &error)) { + } else if (!mm_3gpp_parse_operator_id (str, NULL, NULL, NULL, &error)) { mm_obj_dbg (self, "unexpected operator code string '%s': %s", str, error->message); g_clear_pointer (&str, g_free); } @@ -1442,8 +1440,8 @@ load_operator_code_ready (MMIfaceModem3gpp *self, mm_gdbus_modem3gpp_set_operator_code (ctx->skeleton, str); /* If we also implement the location interface, update the 3GPP location */ - if (mcc && MM_IS_IFACE_MODEM_LOCATION (self)) - mm_iface_modem_location_3gpp_update_mcc_mnc (MM_IFACE_MODEM_LOCATION (self), mcc, mnc); + if (str && MM_IS_IFACE_MODEM_LOCATION (self)) + mm_iface_modem_location_3gpp_update_operator_code (MM_IFACE_MODEM_LOCATION (self), str); g_free (str); @@ -1513,7 +1511,7 @@ mm_iface_modem_3gpp_reload_current_registration_info (MMIfaceModem3gpp *self, if (ctx->operator_code_loaded) { mm_gdbus_modem3gpp_set_operator_code (ctx->skeleton, NULL); if (MM_IS_IFACE_MODEM_LOCATION (self)) - mm_iface_modem_location_3gpp_update_mcc_mnc (MM_IFACE_MODEM_LOCATION (self), 0, 0); + mm_iface_modem_location_3gpp_update_operator_code (MM_IFACE_MODEM_LOCATION (self), NULL); } ctx->operator_name_loaded = !(MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_operator_name && @@ -1538,7 +1536,7 @@ mm_iface_modem_3gpp_clear_current_operator (MMIfaceModem3gpp *self) mm_gdbus_modem3gpp_set_operator_code (skeleton, NULL); mm_gdbus_modem3gpp_set_operator_name (skeleton, NULL); if (MM_IS_IFACE_MODEM_LOCATION (self)) - mm_iface_modem_location_3gpp_update_mcc_mnc (MM_IFACE_MODEM_LOCATION (self), 0, 0); + mm_iface_modem_location_3gpp_update_operator_code (MM_IFACE_MODEM_LOCATION (self), NULL); } /*****************************************************************************/ diff --git a/src/mm-iface-modem-location.c b/src/mm-iface-modem-location.c index b45a3405..792b1ce0 100644 --- a/src/mm-iface-modem-location.c +++ b/src/mm-iface-modem-location.c @@ -345,10 +345,12 @@ notify_3gpp_location_update (MMIfaceModemLocation *self, MmGdbusModemLocation *skeleton, MMLocation3gpp *location_3gpp) { + const gchar *operator_code; + + operator_code = mm_location_3gpp_get_operator_code (location_3gpp); mm_obj_dbg (self, "3GPP location updated " - "(MCC: '%u', MNC: '%u', location area code: '%lX', tracking area code: '%lX', cell ID: '%lX')", - mm_location_3gpp_get_mobile_country_code (location_3gpp), - mm_location_3gpp_get_mobile_network_code (location_3gpp), + "(MCCMNC: '%s', location area code: '%lX', tracking area code: '%lX', cell ID: '%lX')", + operator_code ? operator_code : "<none>", mm_location_3gpp_get_location_area_code (location_3gpp), mm_location_3gpp_get_tracking_area_code (location_3gpp), mm_location_3gpp_get_cell_id (location_3gpp)); @@ -365,9 +367,8 @@ notify_3gpp_location_update (MMIfaceModemLocation *self, } void -mm_iface_modem_location_3gpp_update_mcc_mnc (MMIfaceModemLocation *self, - guint mobile_country_code, - guint mobile_network_code) +mm_iface_modem_location_3gpp_update_operator_code (MMIfaceModemLocation *self, + const gchar *operator_code) { MmGdbusModemLocation *skeleton; LocationContext *ctx; @@ -383,10 +384,8 @@ mm_iface_modem_location_3gpp_update_mcc_mnc (MMIfaceModemLocation *self, guint changed = 0; g_assert (ctx->location_3gpp != NULL); - changed += mm_location_3gpp_set_mobile_country_code (ctx->location_3gpp, - mobile_country_code); - changed += mm_location_3gpp_set_mobile_network_code (ctx->location_3gpp, - mobile_network_code); + changed += mm_location_3gpp_set_operator_code (ctx->location_3gpp, + operator_code); if (changed) notify_3gpp_location_update (self, skeleton, ctx->location_3gpp); } diff --git a/src/mm-iface-modem-location.h b/src/mm-iface-modem-location.h index d00ecc71..c0a7fbd9 100644 --- a/src/mm-iface-modem-location.h +++ b/src/mm-iface-modem-location.h @@ -139,9 +139,8 @@ void mm_iface_modem_location_shutdown (MMIfaceModemLocation *self); /* Update 3GPP (LAC/CI) location */ void mm_iface_modem_location_3gpp_clear (MMIfaceModemLocation *self); -void mm_iface_modem_location_3gpp_update_mcc_mnc (MMIfaceModemLocation *self, - guint mobile_country_code, - guint mobile_network_code); +void mm_iface_modem_location_3gpp_update_operator_code (MMIfaceModemLocation *self, + const gchar *operator_code); void mm_iface_modem_location_3gpp_update_lac_tac_ci (MMIfaceModemLocation *self, gulong location_area_code, gulong tracking_area_code, |