diff options
-rw-r--r-- | debian/control | 12 | ||||
-rw-r--r-- | debian/libosmogb6.install (renamed from debian/libosmogb5.install) | 0 | ||||
-rw-r--r-- | debian/libosmogsm9.install (renamed from debian/libosmogsm8.install) | 0 | ||||
-rw-r--r-- | include/osmocom/gsm/gsm0808.h | 4 | ||||
-rw-r--r-- | include/osmocom/gsm/gsm23003.h | 10 | ||||
-rw-r--r-- | include/osmocom/gsm/gsm48.h | 10 | ||||
-rw-r--r-- | src/gb/Makefile.am | 2 | ||||
-rw-r--r-- | src/gb/gprs_bssgp.c | 5 | ||||
-rw-r--r-- | src/gb/gprs_bssgp_vty.c | 8 | ||||
-rw-r--r-- | src/gsm/Makefile.am | 2 | ||||
-rw-r--r-- | src/gsm/gsm0808.c | 32 | ||||
-rw-r--r-- | src/gsm/gsm23003.c | 129 | ||||
-rw-r--r-- | src/gsm/gsm48.c | 126 | ||||
-rw-r--r-- | src/gsm/libosmogsm.map | 11 | ||||
-rw-r--r-- | src/sim/card_fs_sim.c | 1 |
15 files changed, 277 insertions, 75 deletions
diff --git a/debian/control b/debian/control index 596c3f19..d911f32f 100644 --- a/debian/control +++ b/debian/control @@ -28,8 +28,8 @@ Multi-Arch: foreign Depends: libosmocodec0 (= ${binary:Version}), libosmocoding0 (= ${binary:Version}), libosmocore9 (= ${binary:Version}), - libosmogb5 (= ${binary:Version}), - libosmogsm8 (= ${binary:Version}), + libosmogb6 (= ${binary:Version}), + libosmogsm9 (= ${binary:Version}), libosmovty4 (= ${binary:Version}), libosmoctrl1 (= ${binary:Version}), libosmosim0 (= ${binary:Version}), @@ -146,7 +146,7 @@ Description: Documentation for the Osmo Core library . This package contains the documentation for the libosmocore library. -Package: libosmogb5 +Package: libosmogb6 Section: libs Architecture: any Multi-Arch: same @@ -167,7 +167,7 @@ Package: libosmogb-doc Architecture: all Section: doc Depends: ${misc:Depends}, - libosmogb5, + libosmogb6, libjs-jquery Description: Documentation for the Osmo GPRS Gb library This is part of the libosmocore "meta"-library. The libosmocore library @@ -178,7 +178,7 @@ Description: Documentation for the Osmo GPRS Gb library . This package contains the documentation for the libosmogb library. -Package: libosmogsm8 +Package: libosmogsm9 Section: libs Architecture: any Multi-Arch: same @@ -202,7 +202,7 @@ Package: libosmogsm-doc Architecture: all Section: doc Depends: ${misc:Depends}, - libosmogsm8, + libosmogsm9, libjs-jquery Description: Documentation for the Osmo GSM utility library This is part of the libosmocore "meta"-library. The libosmocore library diff --git a/debian/libosmogb5.install b/debian/libosmogb6.install index 4c474255..4c474255 100644 --- a/debian/libosmogb5.install +++ b/debian/libosmogb6.install diff --git a/debian/libosmogsm8.install b/debian/libosmogsm9.install index 5e617298..5e617298 100644 --- a/debian/libosmogsm8.install +++ b/debian/libosmogsm9.install diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h index 3deee70d..8c276f58 100644 --- a/include/osmocom/gsm/gsm0808.h +++ b/include/osmocom/gsm/gsm0808.h @@ -25,6 +25,8 @@ #include "tlv.h" #include <osmocom/gsm/protocol/gsm_08_08.h> +#include <osmocom/gsm/gsm23003.h> + struct sockaddr_storage; struct msgb; @@ -35,6 +37,8 @@ struct msgb *gsm0808_create_layer3_aoip(const struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, uint16_t _ci, const struct gsm0808_speech_codec_list *scl); +struct msgb *gsm0808_create_layer3_2(const struct msgb *msg_l3, const struct osmo_cell_global_id *cell, + const struct gsm0808_speech_codec_list *scl); struct msgb *gsm0808_create_reset(void); struct msgb *gsm0808_create_reset_ack(void); struct msgb *gsm0808_create_clear_command(uint8_t reason); diff --git a/include/osmocom/gsm/gsm23003.h b/include/osmocom/gsm/gsm23003.h index dd41bc5b..51e5ef83 100644 --- a/include/osmocom/gsm/gsm23003.h +++ b/include/osmocom/gsm/gsm23003.h @@ -9,6 +9,7 @@ struct osmo_plmn_id { uint16_t mcc; uint16_t mnc; + bool mnc_3_digits; /*< ignored and implied true if mnc > 99, otherwise defines leading zeros. */ }; /* 4.1 */ @@ -85,3 +86,12 @@ struct osmo_guti { bool osmo_imsi_str_valid(const char *imsi); bool osmo_msisdn_str_valid(const char *msisdn); + +const char *osmo_mcc_name(uint16_t mcc); +const char *osmo_mnc_name(uint16_t mnc, bool mnc_3_digits); +const char *osmo_plmn_name(const struct osmo_plmn_id *plmn); +const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn); +const char *osmo_lai_name(const struct osmo_location_area_id *lai); + +void osmo_plmn_to_bcd(uint8_t *bcd_dst, const struct osmo_plmn_id *plmn); +void osmo_plmn_from_bcd(const uint8_t *bcd_src, struct osmo_plmn_id *plmn); diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h index 9ec54639..5f144358 100644 --- a/include/osmocom/gsm/gsm48.h +++ b/include/osmocom/gsm/gsm48.h @@ -2,17 +2,21 @@ #pragma once +#include <stdbool.h> + #include <osmocom/gsm/tlv.h> #include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/gsm/gsm48_ie.h> +#include <osmocom/gsm/gsm23003.h> /* reserved according to GSM 03.03 § 2.4 */ #define GSM_RESERVED_TMSI 0xFFFFFFFF /* A parsed GPRS routing area */ struct gprs_ra_id { - uint16_t mnc; uint16_t mcc; + uint16_t mnc; + bool mnc_3_digits; uint16_t lac; uint8_t rac; }; @@ -24,11 +28,15 @@ const char *gsm48_cc_state_name(uint8_t state); const char *gsm48_cc_msg_name(uint8_t msgtype); const char *gsm48_rr_msg_name(uint8_t msgtype); const char *rr_cause_name(uint8_t cause); +const char *osmo_rai_name(const struct gprs_ra_id *rai); int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, uint16_t *mnc, uint16_t *lac); +void gsm48_decode_lai2(const struct gsm48_loc_area_id *lai, struct osmo_location_area_id *decoded); void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, uint16_t mnc, uint16_t lac); +void gsm48_generate_lai2(struct gsm48_loc_area_id *lai48, const struct osmo_location_area_id *lai); + int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi); int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi); uint8_t gsm48_generate_mid(uint8_t *buf, const char *id, uint8_t mi_type); diff --git a/src/gb/Makefile.am b/src/gb/Makefile.am index 1e0aa1e1..70a451d2 100644 --- a/src/gb/Makefile.am +++ b/src/gb/Makefile.am @@ -1,6 +1,6 @@ # This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification -LIBVERSION=5:0:0 +LIBVERSION=6:0:0 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN} -fno-strict-aliasing $(TALLOC_CFLAGS) diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c index 4c0bb8a9..d5d4ea8a 100644 --- a/src/gb/gprs_bssgp.c +++ b/src/gb/gprs_bssgp.c @@ -284,9 +284,8 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, /* actually extract RAC / CID */ bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, TLVP_VAL(tp, BSSGP_IE_CELL_ID)); - LOGP(DBSSGP, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", - bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, - bctx->ra_id.rac, bctx->cell_id, bvci); + LOGP(DBSSGP, LOGL_NOTICE, "Cell %s CI %u on BVCI %u\n", + osmo_rai_name(&bctx->ra_id), bctx->cell_id, bvci); } /* Send NM_BVC_RESET.ind to NM */ diff --git a/src/gb/gprs_bssgp_vty.c b/src/gb/gprs_bssgp_vty.c index 6131e6b1..3af6517f 100644 --- a/src/gb/gprs_bssgp_vty.c +++ b/src/gb/gprs_bssgp_vty.c @@ -81,11 +81,9 @@ DEFUN(cfg_bssgp, cfg_bssgp_cmd, static void dump_bvc(struct vty *vty, struct bssgp_bvc_ctx *bvc, int stats) { - vty_out(vty, "NSEI %5u, BVCI %5u, RA-ID: %u-%u-%u-%u, CID: %u, " - "STATE: %s%s", bvc->nsei, bvc->bvci, bvc->ra_id.mcc, - bvc->ra_id.mnc, bvc->ra_id.lac, bvc->ra_id.rac, bvc->cell_id, - bvc->state & BVC_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", - VTY_NEWLINE); + vty_out(vty, "NSEI %5u, BVCI %5u, RA-ID: %s, CID: %u, " + "STATE: %s%s", bvc->nsei, bvc->bvci, osmo_rai_name(&bvc->ra_id), + bvc->cell_id, bvc->state & BVC_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", VTY_NEWLINE); if (stats) { struct bssgp_flow_control *fc = bvc->fc; diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am index f85aba39..b0d6dbd2 100644 --- a/src/gsm/Makefile.am +++ b/src/gsm/Makefile.am @@ -1,7 +1,7 @@ # This is _NOT_ the library release version, it's an API version. # Please read chapter "Library interface versions" of the libtool documentation # before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html -LIBVERSION=8:0:0 +LIBVERSION=9:0:0 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include $(TALLOC_CFLAGS) AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN} diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c index c0be374d..b43e0e63 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -37,7 +37,8 @@ #define BSSMAP_MSG_SIZE 512 #define BSSMAP_MSG_HEADROOM 128 -/*! Create "Complete L3 Info" for AoIP +/*! Create "Complete L3 Info" for AoIP, legacy implementation. + * Instead use gsm0808_create_layer3_aoip2(), which is capable of three-digit MNC with leading zeros. * \param[in] msg_l3 msgb containing Layer 3 Message * \param[in] nc Mobile Network Code * \param[in] cc Mobile Country Code @@ -50,6 +51,27 @@ struct msgb *gsm0808_create_layer3_aoip(const struct msgb *msg_l3, uint16_t nc, const struct gsm0808_speech_codec_list *scl) { + struct osmo_cell_global_id cgi = { + .lai = { + .plmn = { + .mcc = cc, + .mnc = nc, + }, + .lac = lac, + }, + .cell_identity = _ci, + }; + return gsm0808_create_layer3_2(msg_l3, &cgi, scl); +} + +/*! Create "Complete L3 Info" for AoIP. + * \param[in] msg_l3 msgb containing Layer 3 Message -- not modified by this call. + * \param[in] cell MCC, MNC, LAC, CI to identify the cell. + * \param[in] scl Speech Codec List, optional. + * \returns newly allocated msgb with Complete L3 Info message */ +struct msgb *gsm0808_create_layer3_2(const struct msgb *msg_l3, const struct osmo_cell_global_id *cell, + const struct gsm0808_speech_codec_list *scl) +{ struct msgb* msg; struct { uint8_t ident; @@ -67,8 +89,8 @@ struct msgb *gsm0808_create_layer3_aoip(const struct msgb *msg_l3, uint16_t nc, /* create the cell header */ lai_ci.ident = CELL_IDENT_WHOLE_GLOBAL; - gsm48_generate_lai(&lai_ci.lai, cc, nc, lac); - lai_ci.ci = osmo_htons(_ci); + gsm48_generate_lai2(&lai_ci.lai, &cell->lai); + lai_ci.ci = osmo_htons(cell->cell_identity); msgb_tlv_put(msg, GSM0808_IE_CELL_IDENTIFIER, sizeof(lai_ci), (uint8_t *) &lai_ci); @@ -86,7 +108,9 @@ struct msgb *gsm0808_create_layer3_aoip(const struct msgb *msg_l3, uint16_t nc, return msg; } -/*! Create "Complete L3 Info" for A +/*! Create "Complete L3 Info" for A, legacy implementation. + * Instead use gsm0808_create_layer3_2() with the scl parameter passed as NULL, + * which is capable of three-digit MNC with leading zeros. * \param[in] msg_l3 msgb containing Layer 3 Message * \param[in] nc Mobile Network Code * \param[in] cc Mobile Country Code 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; + } +} diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c index b58e9e2c..c2affaeb 100644 --- a/src/gsm/gsm48.c +++ b/src/gsm/gsm48.c @@ -30,6 +30,7 @@ #include <string.h> #include <stdbool.h> #include <inttypes.h> +#include <ctype.h> #include <osmocom/core/utils.h> #include <osmocom/core/byteswap.h> @@ -180,6 +181,19 @@ const char *rr_cause_name(uint8_t cause) return get_value_string(rr_cause_names, cause); } +/*! Return MCC-MNC-LAC-RAC as string, in a static buffer. + * \param[in] rai RAI to encode. + * \returns Static string buffer. + */ +const char *osmo_rai_name(const struct gprs_ra_id *rai) +{ + static char buf[32]; + snprintf(buf, sizeof(buf), "%s-%s-%u-%u", + osmo_mcc_name(rai->mcc), osmo_mnc_name(rai->mnc, rai->mnc_3_digits), rai->lac, + rai->rac); + return buf; +} + /* FIXME: convert to value_string */ static const char *cc_state_names[32] = { "NULL", @@ -418,15 +432,6 @@ const char *gsm48_mi_type_name(uint8_t mi) return get_value_string(mi_type_names, mi); } -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; -} - /*! Checks is particular message is cipherable in A/Gb mode according to * 3GPP TS 24.008 § 4.7.1.2 * \param[in] hdr Message header @@ -451,64 +456,61 @@ bool gsm48_hdr_gmm_cipherable(const struct gsm48_hdr *hdr) } } -/* 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 - * - * Convert given mcc and mnc to BCD and write to *bcd_dst, which must be an - * allocated buffer of (at least) 3 bytes length. */ +/* Convert MCC + MNC to BCD representation, legacy implementation. + * Instead use osmo_plmn_to_bcd(), which is also capable of converting + * 3-digit MNC that have leading zeros. For parameters, also see there. */ void gsm48_mcc_mnc_to_bcd(uint8_t *bcd_dst, uint16_t mcc, uint16_t mnc) { - uint8_t bcd[3]; - - to_bcd(bcd, mcc); - bcd_dst[0] = bcd[0] | (bcd[1] << 4); - bcd_dst[1] = bcd[2]; - - to_bcd(bcd, mnc); - /* FIXME: do we need three-digit MNC? See Table 10.5.3 */ - if (mnc > 99) { - 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); - } + const struct osmo_plmn_id plmn = { + .mcc = mcc, + .mnc = mnc, + .mnc_3_digits = false, + }; + osmo_plmn_to_bcd(bcd_dst, &plmn); } -/* 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. */ +/* Convert given 3-byte BCD buffer to integers, legacy implementation. + * Instead use osmo_plmn_from_bcd(), which is also capable of converting + * 3-digit MNC that have leading zeros. For parameters, also see there. */ void gsm48_mcc_mnc_from_bcd(uint8_t *bcd_src, uint16_t *mcc, uint16_t *mnc) { - *mcc = (bcd_src[0] & 0x0f) * 100 - + (bcd_src[0] >> 4) * 10 - + (bcd_src[1] & 0x0f); - - if ((bcd_src[1] & 0xf0) == 0xf0) { - *mnc = (bcd_src[2] & 0x0f) * 10 - + (bcd_src[2] >> 4); - } else { - *mnc = (bcd_src[2] & 0x0f) * 100 - + (bcd_src[2] >> 4) * 10 - + (bcd_src[1] >> 4); - } + struct osmo_plmn_id plmn; + osmo_plmn_from_bcd(bcd_src, &plmn); + *mcc = plmn.mcc; + *mnc = plmn.mnc; } -/*! Encode TS 04.08 Location Area Identifier - * \param[out] caller-provided memory for output +/*! Encode TS 04.08 Location Area Identifier, legacy implementation. + * Instead use gsm48_generate_lai2(), which is capable of three-digit MNC with leading zeros. + * \param[out] lai48 caller-provided memory for output * \param[in] mcc Mobile Country Code * \param[in] mnc Mobile Network Code * \param[in] lac Location Area Code */ void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, uint16_t mnc, uint16_t lac) { - gsm48_mcc_mnc_to_bcd(&lai48->digits[0], mcc, mnc); - lai48->lac = osmo_htons(lac); + const struct osmo_location_area_id lai = { + .plmn = { + .mcc = mcc, + .mnc = mnc, + .mnc_3_digits = false, + }, + .lac = lac, + }; + gsm48_generate_lai2(lai48, &lai); +} + +/*! Encode TS 04.08 Location Area Identifier. + * \param[out] lai48 caller-provided memory for output. + * \param[in] lai input of MCC-MNC-LAC. */ +void gsm48_generate_lai2(struct gsm48_loc_area_id *lai48, const struct osmo_location_area_id *lai) +{ + osmo_plmn_to_bcd(&lai48->digits[0], &lai->plmn); + lai48->lac = osmo_htons(lai->lac); } -/*! Decode TS 04.08 Location Area Identifier +/*! Decode TS 04.08 Location Area Identifier, legacy implementation. + * Instead use gsm48_decode_lai2(), which is capable of three-digit MNC with leading zeros. * \param[in] Location Area Identifier (encoded) * \param[out] mcc Mobile Country Code * \param[out] mnc Mobile Network Code @@ -519,11 +521,25 @@ void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, uint16_t *mnc, uint16_t *lac) { - gsm48_mcc_mnc_from_bcd(&lai->digits[0], mcc, mnc); - *lac = osmo_ntohs(lai->lac); + struct osmo_location_area_id decoded; + gsm48_decode_lai2(lai, &decoded); + *mcc = decoded.plmn.mcc; + *mnc = decoded.plmn.mnc; + *lac = decoded.lac; return 0; } +/*! Decode TS 04.08 Location Area Identifier. + * \param[in] Location Area Identifier (encoded). + * \param[out] decoded Target buffer to write decoded values of MCC-MNC-LAC. + * + * Attention: this function returns true integers, not hex! */ +void gsm48_decode_lai2(const struct gsm48_loc_area_id *lai, struct osmo_location_area_id *decoded) +{ + osmo_plmn_from_bcd(&lai->digits[0], &decoded->plmn); + decoded->lac = osmo_ntohs(lai->lac); +} + /*! Set DTX mode in Cell Options IE (3GPP TS 44.018) * \param[in] op Cell Options structure in which DTX parameters will be set * \param[in] full Mode for full-rate channels @@ -682,10 +698,12 @@ void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf) if ((buf[1] >> 4) == 0xf) { raid->mnc = (buf[2] & 0xf) * 10; raid->mnc += (buf[2] >> 4) * 1; + raid->mnc_3_digits = false; } else { raid->mnc = (buf[2] & 0xf) * 100; raid->mnc += (buf[2] >> 4) * 10; raid->mnc += (buf[1] >> 4) * 1; + raid->mnc_3_digits = true; } raid->lac = osmo_load16be(buf + 3); @@ -704,7 +722,7 @@ void gsm48_encode_ra(struct gsm48_ra_id *out, const struct gprs_ra_id *raid) out->digits[0] = ((raid->mcc / 100) % 10) | (((raid->mcc / 10) % 10) << 4); out->digits[1] = raid->mcc % 10; - if (raid->mnc < 100) { + if (raid->mnc < 100 && !raid->mnc_3_digits) { out->digits[1] |= 0xf0; out->digits[2] = ((raid->mnc / 10) % 10) | ((raid->mnc % 10) << 4); } else { diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 7a74718c..531c5c13 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -154,6 +154,7 @@ gsm0808_create_paging; gsm0808_create_dtap; gsm0808_create_layer3; gsm0808_create_layer3_aoip; +gsm0808_create_layer3_2; gsm0808_create_reset; gsm0808_create_reset_ack; gsm0808_create_sapi_reject; @@ -259,6 +260,16 @@ gsm48_dtx_mode; gsm48_mi_type_name; gsm48_mcc_mnc_to_bcd; gsm48_mcc_mnc_from_bcd; +gsm48_generate_lai2; +gsm48_decode_lai2; +osmo_plmn_to_bcd; +osmo_plmn_from_bcd; +osmo_mcc_name; +osmo_mnc_name; +osmo_plmn_name; +osmo_plmn_name2; +osmo_lai_name; +osmo_rai_name; gsm48_chan_mode_names; gsm_chan_t_names; gsm48_pdisc_names; diff --git a/src/sim/card_fs_sim.c b/src/sim/card_fs_sim.c index f66e3913..8c819a4f 100644 --- a/src/sim/card_fs_sim.c +++ b/src/sim/card_fs_sim.c @@ -216,6 +216,7 @@ static int gsm_plmnsel_decode(struct osim_decoded_data *dd, mnc = element_alloc_sub(elem, "MNC", ELEM_T_UINT16, ELEM_REPR_DEC); mnc->u.u16 = ra_id.mnc; + /* TODO: what about ra_id.mnc_3_digits? */ } return 0; |