summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/control12
-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.h4
-rw-r--r--include/osmocom/gsm/gsm23003.h10
-rw-r--r--include/osmocom/gsm/gsm48.h10
-rw-r--r--src/gb/Makefile.am2
-rw-r--r--src/gb/gprs_bssgp.c5
-rw-r--r--src/gb/gprs_bssgp_vty.c8
-rw-r--r--src/gsm/Makefile.am2
-rw-r--r--src/gsm/gsm0808.c32
-rw-r--r--src/gsm/gsm23003.c129
-rw-r--r--src/gsm/gsm48.c126
-rw-r--r--src/gsm/libosmogsm.map11
-rw-r--r--src/sim/card_fs_sim.c1
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;