This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Stefan Sperling gerrit-no-reply at lists.osmocom.orgHello 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 <ssperling at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder