Review at  https://gerrit.osmocom.org/7789

add gsm0808_{enc,dec}_cell_id

Clarify semantics and micro-optimise for the case of single Cell Identifer IEs.
Test in gsm0808_test.c

So far we have gsm0808_enc_cell_id_list2(), but there also exist instances of
single Cell Identifiers (3GPP TS 48.008 3.2.2.17).

It is possible to decode the same using the cell identifier list API, but this
forces the caller to also keep a full struct gsm0808_cell_id_list2 with all its
127 entries around.

E.g. for handover, there are two Cell Identifiers (Serving and Target); I'd
need two full cell id lists for each, and these would be dynamically allocated
for each handover operation, whether it uses them or not.

Related: OS#2283 (inter-BSC HO, BSC side)
Change-Id: I9f9c528965775698ab62ac386af0516192c4b0cc
---
M include/osmocom/gsm/gsm0808_utils.h
M src/gsm/gsm0808_utils.c
M src/gsm/libosmogsm.map
M tests/gsm0808/gsm0808_test.c
M tests/gsm0808/gsm0808_test.ok
5 files changed, 251 insertions(+), 12 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/89/7789/1

diff --git a/include/osmocom/gsm/gsm0808_utils.h 
b/include/osmocom/gsm/gsm0808_utils.h
index 34eae43..8e71b43 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -31,20 +31,27 @@
  /*! (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 @@
                             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 996456e..1c05576 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -988,6 +988,52 @@
        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
+           || (cil.id_discr == CELL_IDENT_BSS && cil.id_list_len != 0)
+           || (cil.id_discr != CELL_IDENT_BSS && 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 4d009e0..388fcc0 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -177,6 +177,8 @@
 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 f467099..13ae3ce 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -1256,6 +1256,174 @@
        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_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 +1455,7 @@
        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 +1467,13 @@
 
        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_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 a049dec..1f51aea 100644
--- a/tests/gsm0808/gsm0808_test.ok
+++ b/tests/gsm0808/gsm0808_test.ok
@@ -104,4 +104,10 @@
 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_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

-- 
To view, visit https://gerrit.osmocom.org/7789
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I9f9c528965775698ab62ac386af0516192c4b0cc
Gerrit-PatchSet: 1
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofm...@sysmocom.de>

Reply via email to