Hello Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/6509

to look at the new patch set (#3).

Support decoding of more cell ID list types in libosmocore.

Extend gsm0808_dec_cell_id_list() with support for more types of
cell identifier lists. The new parsing routines are based on similar
routines used by the paging code in osmo-bsc/osmo_bsc_bssap.c.

There is an API change in struct gsm0808_cell_id_list.
The previous definition was insufficient because it assumed that all
decoded cell ID types could be represented with a single uint16_t.
The only user I am aware of is in osmo-msc, where this struct is used
for one local variable. This API user will be fixed in a follow-up patch.

The function gsm0808_enc_cell_id_list() was adapted to keep the code
compiling but encoding more cell ID list types is left for future work.

Change-Id: Ib7e754f538df0c83298a3c958b4e15a32fcb8abb
Related: OS#2847
---
M include/osmocom/gsm/protocol/gsm_08_08.h
M src/gsm/gsm0808_utils.c
M tests/gsm0808/gsm0808_test.c
3 files changed, 227 insertions(+), 22 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/09/6509/3

diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h 
b/include/osmocom/gsm/protocol/gsm_08_08.h
index ba347ef..75c3c61 100644
--- a/include/osmocom/gsm/protocol/gsm_08_08.h
+++ b/include/osmocom/gsm/protocol/gsm_08_08.h
@@ -502,9 +502,67 @@
 };
 
 /* 3GPP TS 48.008 3.2.2.27 Cell Identifier List */
-#define CELL_ID_LIST_LAC_MAXLEN 127
+
+/*
+ * The structs below are parsed representations of data in the corresponding 
IE.
+ * All fields are in host byte-order.
+ *
+ * The functions gsm0808_dec_cell_id_list() and gsm0808_enc_cell_id_list()
+ * convert these structs from/to a network byte-order data stream.
+ *
+ * XXX TODO: These declarations belong in gsm_0808_utils.h, not here.
+ *           However, moving them there currently breaks the build.
+ */
+
+/* Parsed Cell Global Identification (CELL_IDENT_WHOLE_GLOBAL) */
+struct gsm0808_cell_id_global {
+       uint16_t mcc;
+       uint16_t mnc;
+       uint16_t lac;
+       uint16_t ci;
+}a;
+
+/* Parsed Location Area Code and Cell Identity (CELL_IDENT_LAC_AND_CI) */
+struct gsm0808_cell_id_lac_and_ci {
+       uint16_t lac;
+       uint16_t ci;
+};
+
+/* Parsed Cell Identity (CELL_IDENT_CI) */
+struct gsm0808_cell_id_ci {
+       uint16_t ci;
+};
+
+/* Parsed Location Area Identification and Location Area Code 
(CELL_IDENT_LAI_AND_LAC) */
+struct gsm0808_cell_id_lai_and_lac {
+       uint16_t mcc;
+       uint16_t mnc;
+       uint16_t lac;
+};
+
+/* Parsed Location Area Code (CELL_IDENT_LAC) */
+struct gsm0808_cell_id_lac {
+       uint16_t lac;
+};
+
+#define CELL_ID_LIST_MAXLEN            254     /* implementation-defined 
limit, in bytes */
+#define CELL_ID_LIST_GLOBAL_MAXLEN     (CELL_ID_LIST_MAXLEN / sizeof(struct 
gsm0808_cell_id_global))
+#define CELL_ID_LIST_LAC_AND_CI_MAXLEN (CELL_ID_LIST_MAXLEN / sizeof(struct 
gsm0808_cell_id_lac_and_ci))
+#define CELL_ID_LIST_CI_MAXLEN         (CELL_ID_LIST_MAXLEN / sizeof(struct 
gsm0808_cell_id_ci))
+#define CELL_ID_LIST_LAI_AND_LAC_MAXLEN        (CELL_ID_LIST_MAXLEN / 
sizeof(struct gsm0808_cell_id_lai_and_lac))
+#define CELL_ID_LIST_LAC_MAXLEN                (CELL_ID_LIST_MAXLEN / 
sizeof(struct gsm0808_cell_id_lac))
 struct gsm0808_cell_id_list {
        uint8_t id_discr;
-       uint16_t id_list_lac[CELL_ID_LIST_LAC_MAXLEN];
+       union {
+               /*
+                * All struct fields in elements of these arrays are in 
host-byte order,
+                * ie. contain parsed representations of the data in the 
corresponding IE.
+                */
+               struct gsm0808_cell_id_global           
id_list_global[CELL_ID_LIST_GLOBAL_MAXLEN];
+               struct gsm0808_cell_id_lac_and_ci       
id_list_lac_and_ci[CELL_ID_LIST_LAC_AND_CI_MAXLEN];
+               struct gsm0808_cell_id_ci               
id_list_ci[CELL_ID_LIST_CI_MAXLEN];
+               struct gsm0808_cell_id_lai_and_lac      
id_list_lai_and_lac[CELL_ID_LIST_LAI_AND_LAC_MAXLEN];
+               struct gsm0808_cell_id_lac              
id_list_lac[CELL_ID_LIST_LAC_MAXLEN];
+       } id_list;
        unsigned int id_list_len;
 };
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 93e6074..a2311cc 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <errno.h>
 #include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/gsm48.h>
 
 #define IP_V4_ADDR_LEN 4
 #define IP_V6_ADDR_LEN 16
@@ -590,8 +591,9 @@
        switch (cil->id_discr) {
        case CELL_IDENT_LAC:
                OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN)
-               for (i=0;i<cil->id_list_len;i++) {
-                       msgb_put_u16(msg, cil->id_list_lac[i]);
+               for (i = 0; i < cil->id_list_len; i++) {
+                       const struct gsm0808_cell_id_lac *id_lac = 
&cil->id_list.id_list_lac[i];
+                       msgb_put_u16(msg, id_lac->lac);
                }
                break;
        case CELL_IDENT_BSS:
@@ -606,6 +608,134 @@
        return *tlv_len + 2;
 }
 
+/* Decode 5-byte LAI list element data (see TS 08.08 3.2.2.27) into 
MCC/MNC/LAC.
+ * Return 0 if successful, negative on error. */
+static int
+decode_lai(const uint8_t *data, uint16_t *mcc, uint16_t *mnc, uint16_t *lac)
+{
+       struct gsm48_loc_area_id lai;
+
+       /* Copy data to stack to prevent unaligned access in 
gsm48_decode_lai(). */
+       memcpy(&lai, data, sizeof(lai)); /* don't byte swap yet */
+
+       return gsm48_decode_lai(&lai, mcc, mnc, lac) != 0 ? -1 : 0;
+}
+
+static int
+parse_cell_id_global_list(struct gsm0808_cell_id_global *id_list, unsigned int 
maxlen, const uint8_t *data,
+                         size_t remain, size_t *consumed)
+{
+       struct gsm0808_cell_id_global *id;
+       uint16_t *ci_be;
+       size_t lai_offset;
+       int i = 0;
+
+       *consumed = 0;
+       while (remain >= sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be)) {
+               if (i >= maxlen)
+                       return -ENOSPC;
+               id = &id_list[i];
+               if (decode_lai(&data[lai_offset], &id->mcc, &id->mnc, &id->lac) 
!= 0)
+                       return -EINVAL;
+               lai_offset = 1 + i * (sizeof(struct gsm48_loc_area_id) + 
sizeof(*ci_be));
+               ci_be = (uint16_t *)(&data[lai_offset + sizeof(struct 
gsm48_loc_area_id)]);
+               id->ci = osmo_load16be(ci_be);
+               *consumed += sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be);
+               remain -= sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be);
+               i++;
+       }
+
+       return i;
+}
+
+static int
+parse_cell_id_lac_and_ci_list(struct gsm0808_cell_id_lac_and_ci *id_list, 
unsigned int maxlen, const uint8_t *data,
+                             size_t remain, size_t *consumed)
+{
+       uint16_t *lacp_be, *ci_be;
+       struct gsm0808_cell_id_lac_and_ci *id;
+       int i = 0;
+
+       *consumed = 0;
+
+       if (remain < sizeof(*lacp_be) + sizeof(*ci_be))
+               return -EINVAL;
+
+       lacp_be = (uint16_t *)(&data[0]);
+       ci_be = (uint16_t *)(&data[2]);
+       while (remain >= sizeof(*lacp_be) + sizeof(*ci_be)) {
+               if (i >= maxlen)
+                       return -ENOSPC;
+               id = &id_list[i];
+               id->lac = osmo_load16be(lacp_be);
+               id->ci = osmo_load16be(ci_be);
+               *consumed += sizeof(*lacp_be) + sizeof(*ci_be);
+               remain -= sizeof(*lacp_be) + sizeof(*ci_be);
+               lacp_be++;
+               ci_be++;
+       }
+
+       return i;
+}
+
+static int
+parse_cell_id_ci_list(struct gsm0808_cell_id_ci *id_list, unsigned int maxlen, 
const uint8_t *data, size_t remain,
+                     size_t *consumed)
+{
+       const uint16_t *ci_be = (const uint16_t *)data;
+       int i = 0;
+
+       *consumed = 0;
+       while (remain >= sizeof(*ci_be)) {
+               if (i >= maxlen)
+                       return -ENOSPC;
+               id_list[i++].ci = osmo_load16be(ci_be++);
+               consumed += sizeof(*ci_be);
+               remain -= sizeof(*ci_be);
+       }
+       return i;
+}
+
+static int
+parse_cell_id_lai_and_lac(struct gsm0808_cell_id_lai_and_lac *id_list, 
unsigned int maxlen, const uint8_t *data,
+                         size_t remain, size_t *consumed)
+{
+       struct gsm0808_cell_id_lai_and_lac *id;
+       int i = 0;
+
+       *consumed = 0;
+       while (remain >= sizeof(struct gsm48_loc_area_id)) {
+               if (i >= maxlen)
+                       return -ENOSPC;
+               id = &id_list[i];
+               if (decode_lai(&data[1 + i * sizeof(struct gsm48_loc_area_id)], 
&id->mcc, &id->mnc, &id->lac) != 0)
+                       return -EINVAL;
+               *consumed += sizeof(struct gsm48_loc_area_id);
+               remain -= sizeof(struct gsm48_loc_area_id);
+               i++;
+       }
+
+       return i;
+}
+
+static int
+parse_cell_id_lac_list(struct gsm0808_cell_id_lac *id_list, unsigned int 
maxlen, const uint8_t *data, size_t remain,
+                      size_t *consumed)
+{
+       const uint16_t *lac_be = (const uint16_t *)data;
+       int i = 0;
+
+       *consumed = 0;
+       while (remain >= sizeof(*lac_be)) {
+               if (i >= maxlen)
+                       return -ENOSPC;
+               id_list[i++].lac = osmo_load16be(lac_be++);
+               *consumed += sizeof(*lac_be);
+               remain -= sizeof(*lac_be);
+       }
+       return i;
+}
+
 /*! Decode Cell Identifier List IE
  *  \param[out] cil Caller-provided memory to store Cell ID list
  *  \param[in] elem IE value to be decoded
@@ -615,8 +745,8 @@
                             const uint8_t *elem, uint8_t len)
 {
        uint8_t id_discr;
-       const uint8_t *old_elem = elem;
-       unsigned int item_count = 0;
+       size_t bytes_elem = 0;
+       int list_len = 0;
 
        OSMO_ASSERT(cil);
        if (!elem)
@@ -630,26 +760,43 @@
        elem++;
        len--;
 
-       cil->id_discr = id_discr;
-
        switch (id_discr) {
+       case CELL_IDENT_WHOLE_GLOBAL:
+               list_len = 
parse_cell_id_global_list(cil->id_list.id_list_global, 
CELL_ID_LIST_GLOBAL_MAXLEN, elem, len,
+                                                    &bytes_elem);
+               break;
+       case CELL_IDENT_LAC_AND_CI:
+               list_len = 
parse_cell_id_lac_and_ci_list(cil->id_list.id_list_lac_and_ci, 
CELL_ID_LIST_LAC_AND_CI_MAXLEN,
+                                                        elem, len, 
&bytes_elem);
+               break;
+       case CELL_IDENT_CI:
+               list_len = parse_cell_id_ci_list(cil->id_list.id_list_ci, 
CELL_ID_LIST_CI_MAXLEN, elem, len,
+                                                &bytes_elem);
+               break;
+       case CELL_IDENT_LAI_AND_LAC:
+               list_len = 
parse_cell_id_lai_and_lac(cil->id_list.id_list_lai_and_lac, 
CELL_ID_LIST_LAI_AND_LAC_MAXLEN,
+                                                    elem, len, &bytes_elem);
+               break;
        case CELL_IDENT_LAC:
-               while (len >= 2) {
-                       cil->id_list_lac[item_count] = osmo_load16be(elem);
-                       elem += 2;
-                       item_count++;
-                       len -= 2;
-               }
+               list_len = parse_cell_id_lac_list(cil->id_list.id_list_lac, 
CELL_ID_LIST_LAC_MAXLEN, elem, len,
+                                                 &bytes_elem);
+               break;
        case CELL_IDENT_BSS:
+       case CELL_IDENT_NO_CELL:
                /* Does not have any list items */
                break;
        default:
-               /* FIXME: Implement support for all identifier list elements */
+               /* Remaining cell identification types are not implemented. */
                return -EINVAL;
        }
 
-       cil->id_list_len = item_count;
-       return (int)(elem - old_elem);
+       if (list_len < 0) /* parsing error */
+               return list_len;
+
+       cil->id_discr = id_discr;
+       cil->id_list_len = list_len;
+
+       return 1 + (int)bytes_elem;
 }
 
 /*! Convert the representation of the permitted speech codec identifier
diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c
index 189d548..cf39498 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -458,7 +458,7 @@
        char imsi[] = "001010000001234";
 
        cil.id_discr = CELL_IDENT_LAC;
-       cil.id_list_lac[0] = 0x2342;
+       cil.id_list.id_list_lac[0].lac = 0x2342;
        cil.id_list_len = 1;
 
        printf("Testing creating Paging Request\n");
@@ -759,9 +759,9 @@
 
        memset(&enc_cil, 0, sizeof(enc_cil));
        enc_cil.id_discr = CELL_IDENT_LAC;
-       enc_cil.id_list_lac[0] = 0x0124;
-       enc_cil.id_list_lac[1] = 0xABCD;
-       enc_cil.id_list_lac[2] = 0x5678;
+       enc_cil.id_list.id_list_lac[0].lac = 0x0124;
+       enc_cil.id_list.id_list_lac[1].lac = 0xABCD;
+       enc_cil.id_list.id_list_lac[2].lac = 0x5678;
        enc_cil.id_list_len = 3;
 
        msg = msgb_alloc(1024, "output buffer");
@@ -790,7 +790,7 @@
 
        memset(&enc_cil, 0, sizeof(enc_cil));
        enc_cil.id_discr = CELL_IDENT_LAC;
-       enc_cil.id_list_lac[0] = 0x2342;
+       enc_cil.id_list.id_list_lac[0].lac = 0x2342;
        enc_cil.id_list_len = 1;
 
        msg = msgb_alloc(1024, "output buffer");

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

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Ib7e754f538df0c83298a3c958b4e15a32fcb8abb
Gerrit-PatchSet: 3
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Stefan Sperling <ssperl...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder

Reply via email to