summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gsm/gsm0808_utils.h33
-rw-r--r--src/gsm/gsm0808_utils.c51
-rw-r--r--src/gsm/libosmogsm.map2
-rw-r--r--tests/gsm0808/gsm0808_test.c199
-rw-r--r--tests/gsm0808/gsm0808_test.ok7
5 files changed, 280 insertions, 12 deletions
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index 34eae438..8e71b43c 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -31,20 +31,27 @@ struct sockaddr_storage;
/*! (225-1)/2 is the maximum number of elements in a cell identifier list. */
#define GSM0808_CELL_ID_LIST2_MAXLEN 127
-/*! Parsed representation of a cell identifier list IE. */
+/*! Instead of this, use either struct gsm0808_cell_id or gsm0808_cell_id_list2.
+ * All elements contain parsed representations of the data in the corresponding IE, in host-byte order.
+ */
+union gsm0808_cell_id_u {
+ struct osmo_cell_global_id global;
+ struct osmo_lac_and_ci_id lac_and_ci;
+ uint16_t ci;
+ struct osmo_location_area_id lai_and_lac;
+ uint16_t lac;
+};
+
+/*! Parsed representation of Cell Identifier IE (3GPP TS 48.008 3.2.2.17) */
+struct gsm0808_cell_id {
+ enum CELL_IDENT id_discr;
+ union gsm0808_cell_id_u id;
+};
+
+/*! Parsed representation of a Cell Identifier List IE (3GPP TS 48.008 3.2.2.27). */
struct gsm0808_cell_id_list2 {
enum CELL_IDENT id_discr;
- union {
- /*!
- * All elements of these arrays contain parsed representations of the
- * data in the corresponding IE, in host-byte order.
- */
- struct osmo_cell_global_id global;
- struct osmo_lac_and_ci_id lac_and_ci;
- uint16_t ci;
- struct osmo_location_area_id lai_and_lac;
- uint16_t lac;
- } id_list[GSM0808_CELL_ID_LIST2_MAXLEN];
+ union gsm0808_cell_id_u id_list[GSM0808_CELL_ID_LIST2_MAXLEN];
unsigned int id_list_len;
};
@@ -78,6 +85,8 @@ int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
const uint8_t *elem, uint8_t len)
OSMO_DEPRECATED("use gsm0808_dec_cell_id_list2 instead");
int gsm0808_cell_id_list_add(struct gsm0808_cell_id_list2 *dst, const struct gsm0808_cell_id_list2 *src);
+uint8_t gsm0808_enc_cell_id(struct msgb *msg, const struct gsm0808_cell_id *ci);
+int gsm0808_dec_cell_id(struct gsm0808_cell_id *ci, const uint8_t *elem, uint8_t len);
int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch);
int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
uint8_t perm_spch);
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 996456e1..73d9362e 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -988,6 +988,57 @@ int gsm0808_cell_id_list_add(struct gsm0808_cell_id_list2 *dst, const struct gsm
return added;
}
+/*! Encode Cell Identifier IE (3GPP TS 48.008 3.2.2.17).
+ * \param[out] msg Message Buffer to which IE is to be appended
+ * \param[in] ci Cell ID to be encoded
+ * \returns number of bytes appended to \a msg */
+uint8_t gsm0808_enc_cell_id(struct msgb *msg, const struct gsm0808_cell_id *ci)
+{
+ uint8_t rc;
+ uint8_t *ie_tag;
+ struct gsm0808_cell_id_list2 cil = {
+ .id_discr = ci->id_discr,
+ .id_list = { ci->id },
+ .id_list_len = 1,
+ };
+
+ OSMO_ASSERT(msg);
+ OSMO_ASSERT(ci);
+
+ ie_tag = msg->tail;
+ rc = gsm0808_enc_cell_id_list2(msg, &cil);
+
+ if (rc <= 0)
+ return rc;
+
+ *ie_tag = GSM0808_IE_CELL_IDENTIFIER;
+ return rc;
+}
+
+/*! Decode Cell Identifier IE (3GPP TS 48.008 3.2.2.17).
+ * \param[out] ci Caller-provided memory to store Cell ID.
+ * \param[in] elem IE value to be decoded.
+ * \param[in] len Length of \a elem in bytes.
+ * \returns number of bytes parsed; negative on error */
+int gsm0808_dec_cell_id(struct gsm0808_cell_id *ci, const uint8_t *elem, uint8_t len)
+{
+ struct gsm0808_cell_id_list2 cil;
+ int rc;
+ rc = gsm0808_dec_cell_id_list2(&cil, elem, len);
+ if (rc < 0)
+ return rc;
+ if (cil.id_discr == CELL_IDENT_BSS || cil.id_discr == CELL_IDENT_NO_CELL) {
+ if (cil.id_list_len != 0)
+ return -EINVAL;
+ } else {
+ if (cil.id_list_len != 1)
+ return -EINVAL;
+ }
+ ci->id_discr = cil.id_discr;
+ ci->id = cil.id_list[0];
+ return rc;
+}
+
/*! Convert the representation of the permitted speech codec identifier
* that is used in struct gsm0808_channel_type to the speech codec
* representation we use in struct gsm0808_speech_codec.
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 4d009e04..388fcc04 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -177,6 +177,8 @@ gsm0808_enc_cell_id_list2;
gsm0808_dec_cell_id_list;
gsm0808_dec_cell_id_list2;
gsm0808_cell_id_list_add;
+gsm0808_enc_cell_id;
+gsm0808_dec_cell_id;
gsm0808_chan_type_to_speech_codec;
gsm0808_speech_codec_from_chan_type;
gsm0808_speech_codec_type_names;
diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c
index f4670996..8c184dda 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -1256,6 +1256,196 @@ void test_cell_id_list_add() {
printf("------- %s done\n", __func__);
}
+#define EXPECT_ENCODED(hexstr) do { \
+ const char *enc_str = msgb_hexdump(msg); \
+ printf("%s: encoded: %s(rc = %u)\n", __func__, enc_str, rc_enc); \
+ OSMO_ASSERT(strcmp(enc_str, hexstr " ") == 0); \
+ OSMO_ASSERT(rc_enc == msg->len); \
+ } while(0)
+
+static void test_gsm0808_enc_dec_cell_id_lac()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_LAC,
+ .id.lac = 0x0124,
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ memset(&dec_ci, 0xa5, sizeof(dec_ci));
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 03 05 01 24");
+
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == 3);
+
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr
+ && enc_ci.id.lac == dec_ci.id.lac);
+
+ msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_cell_id_bss()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_BSS,
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 01 06");
+
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == 1);
+
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr);
+
+ msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_cell_id_no_cell()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_NO_CELL,
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 01 03");
+
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == 1);
+
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr);
+
+ msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_cell_id_lai_and_lac()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_LAI_AND_LAC,
+ .id.lai_and_lac = {
+ .plmn = {
+ .mcc = 123,
+ .mnc = 456,
+ },
+ .lac = 0x2342,
+ },
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 06 04 21 63 54 23 42");
+
+ memset(&dec_ci, 0xa5, sizeof(dec_ci));
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == msg->len - 2);
+
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr
+ && osmo_plmn_cmp(&enc_ci.id.lai_and_lac.plmn, &dec_ci.id.lai_and_lac.plmn) == 0
+ && enc_ci.id.lai_and_lac.lac == dec_ci.id.lai_and_lac.lac);
+ msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_cell_id_ci()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_CI,
+ .id.ci = 0x423,
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 03 02 04 23");
+
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == msg->len - 2);
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr
+ && enc_ci.id.ci == dec_ci.id.ci);
+
+ msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_cell_id_lac_and_ci()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_LAC_AND_CI,
+ .id.lac_and_ci = {
+ .lac = 0x423,
+ .ci = 0x235,
+ },
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 05 01 04 23 02 35");
+
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == msg->len - 2);
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr
+ && enc_ci.id.lac_and_ci.lac == dec_ci.id.lac_and_ci.lac
+ && enc_ci.id.lac_and_ci.ci == dec_ci.id.lac_and_ci.ci);
+
+ msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_cell_id_global()
+{
+ struct gsm0808_cell_id enc_ci = {
+ .id_discr = CELL_IDENT_WHOLE_GLOBAL,
+ .id.global = {
+ .lai = {
+ .plmn = { .mcc = 123, .mnc = 456 },
+ .lac = 0x2342
+ },
+ .cell_identity = 0x423,
+ }
+ };
+ struct gsm0808_cell_id dec_ci;
+ struct msgb *msg;
+ uint8_t rc_enc;
+ int rc_dec;
+
+ msg = msgb_alloc(1024, "output buffer");
+ rc_enc = gsm0808_enc_cell_id(msg, &enc_ci);
+ EXPECT_ENCODED("05 08 00 21 63 54 23 42 04 23");
+
+ rc_dec = gsm0808_dec_cell_id(&dec_ci, msg->data + 2, msg->len - 2);
+ OSMO_ASSERT(rc_dec == msg->len - 2);
+
+ OSMO_ASSERT(enc_ci.id_discr == dec_ci.id_discr
+ && osmo_plmn_cmp(&enc_ci.id.global.lai.plmn,
+ &dec_ci.id.global.lai.plmn) == 0
+ && enc_ci.id.global.lai.lac == dec_ci.id.global.lai.lac
+ && enc_ci.id.global.cell_identity == dec_ci.id.global.cell_identity);
+ msgb_free(msg);
+}
+
int main(int argc, char **argv)
{
printf("Testing generation of GSM0808 messages\n");
@@ -1287,6 +1477,7 @@ int main(int argc, char **argv)
test_gsm0808_enc_dec_speech_codec_list();
test_gsm0808_enc_dec_channel_type();
test_gsm0808_enc_dec_encrypt_info();
+
test_gsm0808_enc_dec_cell_id_list_lac();
test_gsm0808_enc_dec_cell_id_list_single_lac();
test_gsm0808_enc_dec_cell_id_list_multi_lac();
@@ -1298,6 +1489,14 @@ int main(int argc, char **argv)
test_cell_id_list_add();
+ test_gsm0808_enc_dec_cell_id_lac();
+ test_gsm0808_enc_dec_cell_id_bss();
+ test_gsm0808_enc_dec_cell_id_no_cell();
+ test_gsm0808_enc_dec_cell_id_lai_and_lac();
+ test_gsm0808_enc_dec_cell_id_ci();
+ test_gsm0808_enc_dec_cell_id_lac_and_ci();
+ test_gsm0808_enc_dec_cell_id_global();
+
printf("Done\n");
return EXIT_SUCCESS;
}
diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok
index a049dec5..27170f27 100644
--- a/tests/gsm0808/gsm0808_test.ok
+++ b/tests/gsm0808/gsm0808_test.ok
@@ -104,4 +104,11 @@ cil.id_list_len = 127
gsm0808_cell_id_list_add(&cil, &cgi2a) --> rc = -28
cil.id_list_len = 127
------- test_cell_id_list_add done
+test_gsm0808_enc_dec_cell_id_lac: encoded: 05 03 05 01 24 (rc = 5)
+test_gsm0808_enc_dec_cell_id_bss: encoded: 05 01 06 (rc = 3)
+test_gsm0808_enc_dec_cell_id_no_cell: encoded: 05 01 03 (rc = 3)
+test_gsm0808_enc_dec_cell_id_lai_and_lac: encoded: 05 06 04 21 63 54 23 42 (rc = 8)
+test_gsm0808_enc_dec_cell_id_ci: encoded: 05 03 02 04 23 (rc = 5)
+test_gsm0808_enc_dec_cell_id_lac_and_ci: encoded: 05 05 01 04 23 02 35 (rc = 7)
+test_gsm0808_enc_dec_cell_id_global: encoded: 05 08 00 21 63 54 23 42 04 23 (rc = 10)
Done