[PATCH] libosmocore[master]: Support decoding of more cell ID list types in libosmocore.

Stefan Sperling gerrit-no-reply at lists.osmocom.org
Fri Feb 16 12:31:13 UTC 2018


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 <ssperling at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder


More information about the gerrit-log mailing list