libosmocore/src/gsm/gsm23003.c

581 lines
19 KiB
C
Raw Normal View History

/*! \file gsm23003.c
* Utility function implementations related to 3GPP TS 23.003 */
/*
* (C) 2017 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <ctype.h>
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/core/utils.h>
static bool is_n_digits(const char *str, int min_digits, int max_digits)
{
int len;
/* Use unsigned char * to avoid a compiler warning of
* "error: array subscript has type 'char' [-Werror=char-subscripts]" */
const unsigned char *pos = (const unsigned char *)str;
if (!pos)
return min_digits < 1;
for (len = 0; *pos && len < max_digits; len++, pos++)
if (!isdigit(*pos))
return false;
if (len < min_digits)
return false;
/* With not too many digits, we should have reached *str == nul */
if (*pos)
return false;
return true;
}
/*! Determine whether the given IMSI is valid according to 3GPP TS 23.003.
* \param imsi IMSI digits in ASCII string representation.
* \returns true when the IMSI is valid, false for invalid characters or number
* of digits.
*/
bool osmo_imsi_str_valid(const char *imsi)
{
return is_n_digits(imsi, GSM23003_IMSI_MIN_DIGITS, GSM23003_IMSI_MAX_DIGITS);
}
/*! Determine whether the given MSISDN is valid according to 3GPP TS 23.003.
* \param msisdn MSISDN digits in ASCII string representation.
* \returns true when the MSISDN is valid, false for invalid characters or number
* of digits.
*/
bool osmo_msisdn_str_valid(const char *msisdn)
{
return is_n_digits(msisdn, GSM23003_MSISDN_MIN_DIGITS, GSM23003_MSISDN_MAX_DIGITS);
}
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
/*! Determine whether the given IMEI is valid according to 3GPP TS 23.003,
* Section 6.2.1. It consists of 14 digits, the 15th check digit is not
* intended for digital transmission.
* \param imei IMEI digits in ASCII string representation.
* \param with_15th_digit when true, expect the 15th digit to be present and
* verify it.
* \returns true when the IMEI is valid, false for invalid characters or number
* of digits.
*/
bool osmo_imei_str_valid(const char *imei, bool with_15th_digit)
{
if (with_15th_digit)
return is_n_digits(imei, 15, 15) && osmo_luhn(imei, 14) == imei[14];
else
return is_n_digits(imei, 14, 14);
}
/*! Return MCC string as standardized 3-digit with leading zeros.
* \param[out] buf caller-allocated output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] mcc MCC value.
* \returns string in user-supplied output buffer
*/
char *osmo_mcc_name_buf(char *buf, size_t buf_len, uint16_t mcc)
{
snprintf(buf, buf_len, "%03u", mcc);
return buf;
}
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
/*! Return MCC string as standardized 3-digit with leading zeros.
* \param[in] mcc MCC value.
* \returns string in static buffer.
*/
const char *osmo_mcc_name(uint16_t mcc)
{
static __thread char buf[8];
return osmo_mcc_name_buf(buf, sizeof(buf), mcc);
}
/*! Return MCC string as standardized 3-digit with leading zeros, into a talloc-allocated buffer.
* \param[in] ctx talloc context from which to allocate output buffer
* \param[in] mcc MCC value.
* \returns string in dynamically allocated buffer.
*/
const char *osmo_mcc_name_c(const void *ctx, uint16_t mcc)
{
char *buf = talloc_size(ctx, 8);
if (!buf)
return NULL;
return osmo_mcc_name_buf(buf, 8, mcc);
}
/*! Return MNC string as standardized 2- or 3-digit with leading zeros.
* \param[out] buf caller-allocated output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] mnc MNC value.
* \param[in] mnc_3_digits True if an MNC should fill three digits, only has an effect if MNC < 100.
* \returns string in static buffer.
*/
char *osmo_mnc_name_buf(char *buf, size_t buf_len, uint16_t mnc, bool mnc_3_digits)
{
snprintf(buf, buf_len, "%0*u", mnc_3_digits ? 3 : 2, mnc);
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
return buf;
}
/*! Return MNC string as standardized 2- or 3-digit with leading zeros, into a talloc-allocated buffer.
* \param[in] ctx talloc context from which to allocate output buffer
* \param[in] mnc MNC value.
* \param[in] mnc_3_digits True if an MNC should fill three digits, only has an effect if MNC < 100.
* \returns string in dynamically allocated buffer.
*/
char *osmo_mnc_name_c(const void *ctx, uint16_t mnc, bool mnc_3_digits)
{
char *buf = talloc_size(ctx, 8);
if (!buf)
return buf;
return osmo_mnc_name_buf(buf, 8, mnc, mnc_3_digits);
}
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
/*! Return MNC string as standardized 2- or 3-digit with leading zeros.
* \param[in] mnc MNC value.
* \param[in] mnc_3_digits True if an MNC should fill three digits, only has an effect if MNC < 100.
* \returns string in static buffer.
*/
const char *osmo_mnc_name(uint16_t mnc, bool mnc_3_digits)
{
static __thread char buf[8];
return osmo_mnc_name_buf(buf, sizeof(buf), mnc, mnc_3_digits);
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
}
/*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros.
* \param[out] buf caller-allocated output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] plmn MCC-MNC value.
* \returns string in static buffer.
*/
char *osmo_plmn_name_buf(char *buf, size_t buf_len, const struct osmo_plmn_id *plmn)
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
{
char mcc[8], mnc[8];
snprintf(buf, buf_len, "%s-%s", osmo_mcc_name_buf(mcc, sizeof(mcc), plmn->mcc),
osmo_mnc_name_buf(mnc, sizeof(mnc), plmn->mnc, plmn->mnc_3_digits));
return buf;
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
}
/*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros.
* \param[in] plmn MCC-MNC value.
* \returns string in static buffer.
*/
const char *osmo_plmn_name(const struct osmo_plmn_id *plmn)
{
static __thread char buf[16];
return osmo_plmn_name_buf(buf, sizeof(buf), plmn);
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
}
/*! Same as osmo_plmn_name(), but returning in a different static buffer.
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
* \param[in] plmn MCC-MNC value.
* \returns string in static buffer.
*/
const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn)
{
static __thread char buf[16];
return osmo_plmn_name_buf(buf, sizeof(buf), plmn);
}
/*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros, into
* a dynamically-allocated output buffer.
* \param[in] ctx talloc context from which to allocate output buffer
* \param[in] plmn MCC-MNC value.
* \returns string in dynamically allocated buffer.
*/
char *osmo_plmn_name_c(const void *ctx, const struct osmo_plmn_id *plmn)
{
char *buf = talloc_size(ctx, 16);
if (!buf)
return NULL;
return osmo_plmn_name_buf(buf, 16, plmn);
}
/*! Return MCC-MNC-LAC as string, in caller-provided output buffer.
* \param[out] buf caller-allocated output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] lai LAI to encode, the rac member is ignored.
* \returns buf
*/
char *osmo_lai_name_buf(char *buf, size_t buf_len, const struct osmo_location_area_id *lai)
{
char plmn[16];
snprintf(buf, buf_len, "%s-%u", osmo_plmn_name_buf(plmn, sizeof(plmn), &lai->plmn), lai->lac);
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
return buf;
}
/*! Return MCC-MNC-LAC as string, in a static buffer.
* \param[in] lai LAI to encode, the rac member is ignored.
* \returns Static string buffer.
*/
const char *osmo_lai_name(const struct osmo_location_area_id *lai)
{
static __thread char buf[32];
return osmo_lai_name_buf(buf, sizeof(buf), lai);
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
}
/*! Return MCC-MNC-LAC as string, in a talloc-allocated output buffer.
* \param[in] ctx talloc context from which to allocate output buffer
* \param[in] lai LAI to encode, the rac member is ignored.
* \returns string representation of lai in dynamically allocated buffer.
*/
char *osmo_lai_name_c(const void *ctx, const struct osmo_location_area_id *lai)
{
char *buf = talloc_size(ctx, 32);
if (!buf)
return NULL;
return osmo_lai_name_buf(buf, 32, lai);
}
/*! Return MCC-MNC-LAC-CI as string, in caller-provided output buffer.
* \param[out] buf caller-allocated output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] cgi CGI to encode.
* \returns buf
*/
char *osmo_cgi_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id *cgi)
{
snprintf(buf, buf_len, "%s-%u", osmo_lai_name(&cgi->lai), cgi->cell_identity);
return buf;
}
/*! Return MCC-MNC-LAC-CI as string, in a static buffer.
* \param[in] cgi CGI to encode.
* \returns Static string buffer.
*/
const char *osmo_cgi_name(const struct osmo_cell_global_id *cgi)
{
static __thread char buf[32];
return osmo_cgi_name_buf(buf, sizeof(buf), cgi);
}
/*! Same as osmo_cgi_name(), but uses a different static buffer.
* Useful for printing two distinct CGIs in the same printf format.
* \param[in] cgi CGI to encode.
* \returns Static string buffer.
*/
const char *osmo_cgi_name2(const struct osmo_cell_global_id *cgi)
{
static __thread char buf[32];
return osmo_cgi_name_buf(buf, sizeof(buf), cgi);
}
/*! Return MCC-MNC-LAC-CI as string, in a talloc-allocated output buffer.
* \param[in] ctx talloc context from which to allocate output buffer
* \param[in] cgi CGI to encode.
* \returns string representation of CGI in dynamically-allocated buffer.
*/
char *osmo_cgi_name_c(const void *ctx, const struct osmo_cell_global_id *cgi)
{
char *buf = talloc_size(ctx, 32);
return osmo_cgi_name_buf(buf, 32, cgi);
}
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
static void to_bcd(uint8_t *bcd, uint16_t val)
{
bcd[2] = val % 10;
val = val / 10;
bcd[1] = val % 10;
val = val / 10;
bcd[0] = val % 10;
}
/*! Return string representation of GUMMEI in caller-provided output buffer.
* \param[out] buf pointer to caller-provided output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] gummei GUMMEI to be stringified
* \returns buf
*/
char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei)
{
char plmn[16];
snprintf(buf, buf_len, "%s-%04x-%02x", osmo_plmn_name_buf(plmn, sizeof(plmn), &gummei->plmn),
gummei->mme.group_id, gummei->mme.code);
return buf;
}
/*! Return string representation of GUMMEI in static output buffer.
* \param[in] gummei GUMMEI to be stringified
* \returns pointer to static output buffer
*/
const char *osmo_gummei_name(const struct osmo_gummei *gummei)
{
static __thread char buf[32];
return osmo_gummei_name_buf(buf, sizeof(buf), gummei);
}
/*! Return string representation of GUMMEI in static output buffer.
* \param[out] buf pointer to caller-provided output buffer
* \param[in] buf_len size of buf in bytes
* \param[in] gummei GUMMEI to be stringified
* \returns pointer to static output buffer
*/
char *osmo_gummei_name_c(const void *ctx, const struct osmo_gummei *gummei)
{
char *buf = talloc_size(ctx, 32);
if (!buf)
return NULL;
return osmo_gummei_name_buf(buf, 32, gummei);
}
implement support for 3-digit MNC with leading zeros Enable representing three-digit MNC with leading zeros. The MNCs 23 and 023 are actually different; so far we treated both as 23. Re-encode an incoming BCD or string of 023 as it were, i.e. not dropping the leading zero as 23. Break ABI compatibility by changing the size and ordering of structs gprs_ra_id, osmo_plmn_id, osmo_cell_global_id, ... by adding an mnc_3_digits flag. Change ordering in gprs_ra_id because the canonical oder is {Mobile Country Code, Mobile Network Code}, so have the mcc member first. ABI compatibility cannot be maintained for struct gprs_ra_id, since it is a direct member of structs bssgp_bvc_ctx and bssgp_paging_info, and even just adding a flag to the end would cause ABI changes of those structs. Similarly, osmo_plmn_id is a direct member of osmo_location_area_id, and so forth. Add new API to set and read this additional flag to preserve leading zeros: - osmo_plmn_to_bcd(), osmo_plmn_from_bcd() after gsm48_mcc_mnc_to_bcd() and gsm48_mcc_mnc_from_bcd(). - gsm48_decode_lai2(), gsm48_generate_lai2() after gsm48_decode_lai(), gsm48_generate_lai(). - gsm0808_create_layer3_2() after gsm0808_create_layer3() and gsm0808_create_layer3_aoip(). - various osmo_*_name() functions in gsm23003.h (osmo_rai_name() still in gsm48.h close to struct gprs_ra_id definition). The amount and duplication of these may seem a bit overboard, but IMO they do make sense in this way. Though most code will soon see patches unifying the data structures used, in some cases (vty, ctrl) they are required singled out. Without these functions, the formatting ("%0*u", mnc_3_digits ? 3 : 2, mnc) would be duplicated all over our diverse repositories. In various log output, include the leading MNC zeros. Mark one TODO in card_fs_sim.c, I am not sure how to communicate a leading zero to/from a SIM card FS. The focus here is on the core network / BSS. To indicate ABI incompatibility, bump libosmogsm and libosmogb LIBVERSIONs; adjust debian files accordingly. Implementation choices: - The default behavior upon zero-initialization will be the mnc_3_digits flag set to false, which yields exactly the previous behavior. - I decided against packing the mnc with the mnc_3_digits field into a sub-struct because it would immediately break all builds of dependent projects: it would require immediate merging of numerous patches in other repositories, and it would make compiling older code against a newer libosmocore unneccessarily hard. Change-Id: Id2240f7f518494c9df6c8bda52c0d5092f90f221
2018-02-20 12:47:08 +00:00
/* Convert MCC + MNC to BCD representation
* \param[out] bcd_dst caller-allocated memory for output
* \param[in] mcc Mobile Country Code
* \param[in] mnc Mobile Network Code
* \param[in] mnc_3_digits true if the MNC shall have three digits.
*
* Convert given mcc and mnc to BCD and write to *bcd_dst, which must be an
* allocated buffer of (at least) 3 bytes length. Encode the MNC in three
* digits if its integer value is > 99, or if mnc_3_digits is passed true.
* Encode an MNC < 100 with mnc_3_digits passed as true as a three-digit MNC
* with leading zeros in the BCD representation.
*/
void osmo_plmn_to_bcd(uint8_t *bcd_dst, const struct osmo_plmn_id *plmn)
{
uint8_t bcd[3];
to_bcd(bcd, plmn->mcc);
bcd_dst[0] = bcd[0] | (bcd[1] << 4);
bcd_dst[1] = bcd[2];
to_bcd(bcd, plmn->mnc);
if (plmn->mnc > 99 || plmn->mnc_3_digits) {
bcd_dst[1] |= bcd[2] << 4;
bcd_dst[2] = bcd[0] | (bcd[1] << 4);
} else {
bcd_dst[1] |= 0xf << 4;
bcd_dst[2] = bcd[1] | (bcd[2] << 4);
}
}
/* Convert given 3-byte BCD buffer to integers and write results to *mcc and
* *mnc. The first three BCD digits result in the MCC and the remaining ones in
* the MNC. Return mnc_3_digits as false if the MNC's most significant digit is encoded as 0xF, true
* otherwise; i.e. true if MNC > 99 or if it is represented with leading zeros instead of 0xF.
* \param[in] bcd_src 3-byte BCD buffer containing MCC+MNC representations.
* \param[out] mcc MCC result buffer, or NULL.
* \param[out] mnc MNC result buffer, or NULL.
* \param[out] mnc_3_digits Result buffer for 3-digit flag, or NULL.
*/
void osmo_plmn_from_bcd(const uint8_t *bcd_src, struct osmo_plmn_id *plmn)
{
plmn->mcc = (bcd_src[0] & 0x0f) * 100
+ (bcd_src[0] >> 4) * 10
+ (bcd_src[1] & 0x0f);
if ((bcd_src[1] & 0xf0) == 0xf0) {
plmn->mnc = (bcd_src[2] & 0x0f) * 10
+ (bcd_src[2] >> 4);
plmn->mnc_3_digits = false;
} else {
plmn->mnc = (bcd_src[2] & 0x0f) * 100
+ (bcd_src[2] >> 4) * 10
+ (bcd_src[1] >> 4);
plmn->mnc_3_digits = true;
}
}
/* Convert string to MNC, detecting 3-digit MNC with leading zeros.
* Return mnc_3_digits as false if the MNC's most significant digit is encoded as 0xF, true
* otherwise; i.e. true if MNC > 99 or if it is represented with leading zeros instead of 0xF.
* \param mnc_str[in] String representation of an MNC, with or without leading zeros.
* \param mnc[out] MNC result buffer, or NULL.
* \param[out] mnc_3_digits Result buffer for 3-digit flag, or NULL.
* \returns zero on success, -EINVAL in case of surplus characters, negative errno in case of conversion
* errors. In case of error, do not modify the out-arguments.
*/
int osmo_mnc_from_str(const char *mnc_str, uint16_t *mnc, bool *mnc_3_digits)
{
long int _mnc = 0;
bool _mnc_3_digits = false;
char *endptr;
int rc = 0;
if (!mnc_str || !isdigit((unsigned char)mnc_str[0]) || strlen(mnc_str) > 3)
return -EINVAL;
errno = 0;
_mnc = strtol(mnc_str, &endptr, 10);
if (errno)
rc = -errno;
else if (*endptr)
return -EINVAL;
if (_mnc < 0 || _mnc > 999)
return -ERANGE;
_mnc_3_digits = strlen(mnc_str) > 2;
if (mnc)
*mnc = (uint16_t)_mnc;
if (mnc_3_digits)
*mnc_3_digits = _mnc_3_digits;
return rc;
}
/* Compare two MNC with three-digit flag.
* The mnc_3_digits flags passed in only have an effect if the MNC are < 100, i.e. if they would amount
* to a change in leading zeros in a BCD representation. An MNC >= 100 implies three digits, and the flag
* is actually ignored.
* \param a_mnc[in] "Left" side MNC.
* \param a_mnc_3_digits[in] "Left" side three-digits flag.
* \param b_mnc[in] "Right" side MNC.
* \param b_mnc_3_digits[in] "Right" side three-digits flag.
* \returns 0 if the MNC are equal, -1 if a < b or a shorter, 1 if a > b or a longer. */
int osmo_mnc_cmp(uint16_t a_mnc, bool a_mnc_3_digits, uint16_t b_mnc, bool b_mnc_3_digits)
{
if (a_mnc < b_mnc)
return -1;
if (a_mnc > b_mnc)
return 1;
/* a_mnc == b_mnc, but same amount of leading zeros? */
if (a_mnc < 100 && a_mnc_3_digits != b_mnc_3_digits)
return a_mnc_3_digits ? 1 : -1;
return 0;
}
/* Compare two PLMN.
* \param a[in] "Left" side PLMN.
* \param b[in] "Right" side PLMN.
* \returns 0 if the PLMN are equal, -1 if a < b or a shorter, 1 if a > b or a longer. */
int osmo_plmn_cmp(const struct osmo_plmn_id *a, const struct osmo_plmn_id *b)
{
if (a == b)
return 0;
if (a->mcc < b->mcc)
return -1;
if (a->mcc > b->mcc)
return 1;
return osmo_mnc_cmp(a->mnc, a->mnc_3_digits, b->mnc, b->mnc_3_digits);
}
/* Compare two LAI.
* The order of comparison is MCC, MNC, LAC. See also osmo_plmn_cmp().
* \param a[in] "Left" side LAI.
* \param b[in] "Right" side LAI.
* \returns 0 if the LAI are equal, -1 if a < b, 1 if a > b. */
int osmo_lai_cmp(const struct osmo_location_area_id *a, const struct osmo_location_area_id *b)
{
int rc = osmo_plmn_cmp(&a->plmn, &b->plmn);
if (rc)
return rc;
if (a->lac < b->lac)
return -1;
if (a->lac > b->lac)
return 1;
return 0;
}
/* Compare two CGI.
* The order of comparison is MCC, MNC, LAC, CI. See also osmo_lai_cmp().
* \param a[in] "Left" side CGI.
* \param b[in] "Right" side CGI.
* \returns 0 if the CGI are equal, -1 if a < b, 1 if a > b. */
int osmo_cgi_cmp(const struct osmo_cell_global_id *a, const struct osmo_cell_global_id *b)
{
int rc = osmo_lai_cmp(&a->lai, &b->lai);
if (rc)
return rc;
if (a->cell_identity < b->cell_identity)
return -1;
if (a->cell_identity > b->cell_identity)
return 1;
return 0;
}
/*! Generate TS 23.003 Section 19.2 Home Network Realm/Domain (text form)
* \param out[out] caller-provided output buffer, at least 33 bytes long
* \param plmn[in] Osmocom representation of PLMN ID (MCC + MNC)
* \returns number of characters printed (excluding NUL); negative on error */
int osmo_gen_home_network_domain(char *out, const struct osmo_plmn_id *plmn)
{
if (plmn->mcc > 999)
return -EINVAL;
if (plmn->mnc > 999)
return -EINVAL;
return sprintf(out, "epc.mnc%03u.mcc%03u.3gppnetwork.org", plmn->mnc, plmn->mcc);
}
/*! Parse a TS 23.003 Section 19.2 Home Network Realm/Domain (text form) into a \ref osmo_plmn_id
* \param out[out] caller-allocated output structure
* \param in[in] character string representation to be parsed
* \returns 0 on success; negative on error */
int osmo_parse_home_network_domain(struct osmo_plmn_id *out, const char *in)
{
int rc;
memset(out, 0, sizeof(*out));
rc = sscanf(in, "epc.mnc%03hu.mcc%03hu.3gppnetwork.org", &out->mnc, &out->mcc);
if (rc < 0)
return rc;
if (rc != 2)
return -EINVAL;
return 0;
}
/*! Generate TS 23.003 Section 19.4.2.4 MME Domain (text form)
* \param out[out] caller-provided output buffer, at least 56 bytes long
* \param gummei[in] Structure representing the Globally Unique MME Identifier
* \returns number of characters printed (excluding NUL); negative on error */
int osmo_gen_mme_domain(char *out, const struct osmo_gummei *gummei)
{
char domain[GSM23003_HOME_NETWORK_DOMAIN_LEN+1];
int rc;
rc = osmo_gen_home_network_domain(domain, &gummei->plmn);
if (rc < 0)
return rc;
return sprintf(out, "mmec%02x.mmegi%04x.mme.%s", gummei->mme.code, gummei->mme.group_id, domain);
}
/*! Parse a TS 23.003 Section 19.4.2.4 MME Domain (text form) into a \ref osmo_gummei
* \param out[out] caller-allocated output GUMMEI structure
* \param in[in] character string representation to be parsed
* \returns 0 on success; negative on error */
int osmo_parse_mme_domain(struct osmo_gummei *out, const char *in)
{
int rc;
memset(out, 0, sizeof(*out));
rc = sscanf(in, "mmec%02hhx.mmegi%04hx.mme.epc.mnc%03hu.mcc%03hu.3gppnetwork.org",
&out->mme.code, &out->mme.group_id,
&out->plmn.mnc, &out->plmn.mcc);
if (rc < 0)
return rc;
if (rc != 4)
return -EINVAL;
return 0;
}
/*! Generate TS 23.003 Section 19.4.2.4 MME Group Domain (text form)
* \param out[out] caller-provided output buffer, at least 56 bytes long
* \param mmegi[in] MME Group Identifier
* \param plmn[in] Osmocom representation of PLMN ID (MCC + MNC)
* \returns number of characters printed (excluding NUL); negative on error */
int osmo_gen_mme_group_domain(char *out, uint16_t mmegi, const struct osmo_plmn_id *plmn)
{
char domain[GSM23003_HOME_NETWORK_DOMAIN_LEN+1];
int rc;
rc = osmo_gen_home_network_domain(domain, plmn);
if (rc < 0)
return rc;
return sprintf(out, "mmegi%04x.mme.%s", mmegi, domain);
}