diff options
author | Teijo Kinnunen <teijo.kinnunen@uros.com> | 2021-05-06 14:35:41 +0300 |
---|---|---|
committer | Teijo Kinnunen <teijo.kinnunen@uros.com> | 2021-05-17 12:46:52 +0300 |
commit | 879ec1a5d4418ae1dfc137844fd2c06a35ffeabf (patch) | |
tree | 1a369fa46adc9586c239c60967d17710b1421546 /libmm-glib/mm-location-3gpp.c | |
parent | 14c4f27ae4a0ccdfec29090b9abd77112fec1516 (diff) | |
download | ModemManager-879ec1a5d4418ae1dfc137844fd2c06a35ffeabf.tar.gz |
libmm-glib,iface-modem-location: add MMLocation3gpp 3 digit MNC support
MMLocation3gpp provides MCC/MNC information as integers, so it can not
make distinction between operator codes such as XXX01 and XXX001.
This commit deprecates mm_location_3gpp_get_mobile_network_code() and
implements a new function mm_location_3gpp_get_operator_code() which
provides the MCC+MNC in string format.
The mm_location_3gpp_get_mobile_country_code() is still available as
returning the MCC as an integer does not have ambiguity issues.
Diffstat (limited to 'libmm-glib/mm-location-3gpp.c')
-rw-r--r-- | libmm-glib/mm-location-3gpp.c | 284 |
1 files changed, 167 insertions, 117 deletions
diff --git a/libmm-glib/mm-location-3gpp.c b/libmm-glib/mm-location-3gpp.c index c23aeec51..92e20f118 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; } |