diff options
Diffstat (limited to 'src/gsm/gsm23003.c')
-rw-r--r-- | src/gsm/gsm23003.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c index 95ac9f83..63de2b81 100644 --- a/src/gsm/gsm23003.c +++ b/src/gsm/gsm23003.c @@ -24,6 +24,7 @@ */ #include <ctype.h> +#include <stdio.h> #include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/protocol/gsm_23_003.h> @@ -66,3 +67,131 @@ bool osmo_msisdn_str_valid(const char *msisdn) { return is_n_digits(msisdn, 1, 15); } + +/*! 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 char buf[8]; + snprintf(buf, sizeof(buf), "%03u", mcc); + return buf; +} + +/*! 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 char buf[8]; + snprintf(buf, sizeof(buf), "%0*u", mnc_3_digits ? 3 : 2, mnc); + return buf; +} + +static inline void plmn_name(char *buf, size_t buflen, const struct osmo_plmn_id *plmn) +{ + snprintf(buf, buflen, "%s-%s", osmo_mcc_name(plmn->mcc), + osmo_mnc_name(plmn->mnc, plmn->mnc_3_digits)); +} + +/*! 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 char buf[16]; + plmn_name(buf, sizeof(buf), plmn); + return buf; +} + +/*! Same as osmo_mcc_mnc_name(), but returning in a different static buffer. + * \param[in] plmn MCC-MNC value. + * \returns string in static buffer. + */ +const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn) +{ + static char buf[16]; + plmn_name(buf, sizeof(buf), plmn); + 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 char buf[32]; + snprintf(buf, sizeof(buf), "%s-%u", osmo_plmn_name(&lai->plmn), lai->lac); + return buf; +} + +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; +} + +/* 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; + } +} |