aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-02-20 13:47:08 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2018-02-28 19:26:33 +0100
commitc4fce1425e19d604c199c895e227dc2519110456 (patch)
tree0eecba6800e7ac3a714d8a7b7183b6c44bb09f40
parent8fd85578bc7174155e1bb9e98a0d7cdbf85749af (diff)
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
-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 596c3f1..d911f32 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 4c47425..4c47425 100644
--- a/debian/libosmogb5.install
+++ b/debian/libosmogb6.install
diff --git a/debian/libosmogsm8.install b/debian/libosmogsm9.install
index 5e61729..5e61729 100644
--- a/debian/libosmogsm8.install
+++ b/debian/libosmogsm9.install
diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h
index 3deee70..8c276f5 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 dd41bc5..51e5ef8 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 9ec5463..5f14435 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 1e0aa1e..70a451d 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 4c0bb8a..d5d4ea8 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 6131e6b..3af6517 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 f85aba3..b0d6dbd 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 c0be374..b43e0e6 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 95ac9f8..63de2b8 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 b58e9e2..c2affae 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 7a74718..531c5c1 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 f66e391..8c819a4 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;