[PATCH] libosmocore[master]: support for more cell ID list types in libosmocore

Stefan Sperling gerrit-no-reply at lists.osmocom.org
Tue Feb 20 09:27:40 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 (#6).

support for more cell ID list types in libosmocore

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

Likewise, extend gsm0808_enc_cell_id_list() with support for the
same additional types of cell identifier lists.

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.
It was declared in a GSM protocol header (gsm/protocol/gsm_08_08.h)
despite being a host-side representation of data in an IE.
The only user I am aware of is in osmo-msc, where this struct is used
for one local variable.
This API user is fixed by https://gerrit.osmocom.org/#/c/6518/

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


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

diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h
index 3deee70..219e339 100644
--- a/include/osmocom/gsm/gsm0808.h
+++ b/include/osmocom/gsm/gsm0808.h
@@ -28,6 +28,7 @@
 struct sockaddr_storage;
 
 struct msgb;
+struct gsm0808_cell_id_list;
 
 struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc,
 				   uint16_t cc, int lac, uint16_t _ci);
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index 7432164..3efadf8 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -26,6 +26,62 @@
 struct sockaddr_storage;
 
 #include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/gsm23003.h>
+
+/* 3GPP TS 48.008 3.2.2.27 Cell Identifier List */
+
+/*
+ * 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.
+ */
+
+/* Parsed Cell Global Identification (CELL_IDENT_WHOLE_GLOBAL)
+ * uses struct osmo_cell_global_id. */
+
+/* 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)
+ * uses struct osmo_location_area_id. */
+
+/* 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 osmo_cell_global_id))
+#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 osmo_location_area_id))
+#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;
+	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 osmo_cell_global_id		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 osmo_location_area_id		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;
+};
+
 
 uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
 				    const struct sockaddr_storage *ss);
diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h
index ba347ef..e8d6911 100644
--- a/include/osmocom/gsm/protocol/gsm_08_08.h
+++ b/include/osmocom/gsm/protocol/gsm_08_08.h
@@ -500,11 +500,3 @@
 	uint8_t key[ENCRY_INFO_KEY_MAXLEN];
 	unsigned int key_len;
 };
-
-/* 3GPP TS 48.008 3.2.2.27 Cell Identifier List */
-#define CELL_ID_LIST_LAC_MAXLEN 127
-struct gsm0808_cell_id_list {
-	uint8_t id_discr;
-	uint16_t id_list_lac[CELL_ID_LIST_LAC_MAXLEN];
-	unsigned int id_list_len;
-};
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 93e6074..72c226a 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -27,6 +27,8 @@
 #include <string.h>
 #include <errno.h>
 #include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/gsm0808_utils.h>
 
 #define IP_V4_ADDR_LEN 4
 #define IP_V6_ADDR_LEN 16
@@ -588,22 +590,180 @@
 	msgb_put_u8(msg, cil->id_discr & 0x0f);
 
 	switch (cil->id_discr) {
+	case CELL_IDENT_WHOLE_GLOBAL:
+		OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_GLOBAL_MAXLEN)
+		for (i = 0; i < cil->id_list_len; i++) {
+			const struct osmo_cell_global_id *id = &cil->id_list.id_list_global[i];
+			struct gsm48_loc_area_id lai;
+			gsm48_generate_lai(&lai, id->lai.plmn.mcc, id->lai.plmn.mnc, id->lai.lac);
+			memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai));
+			msgb_put_u16(msg, id->cell_identity);
+		}
+		break;
+	case CELL_IDENT_LAC_AND_CI:
+		OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_AND_CI_MAXLEN)
+		for (i = 0; i < cil->id_list_len; i++) {
+			const struct gsm0808_cell_id_lac_and_ci *id = &cil->id_list.id_list_lac_and_ci[i];
+			msgb_put_u16(msg, id->lac);
+			msgb_put_u16(msg, id->ci);
+		}
+		break;
+	case CELL_IDENT_CI:
+		OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_CI_MAXLEN)
+		for (i = 0; i < cil->id_list_len; i++) {
+			const struct gsm0808_cell_id_ci *id = &cil->id_list.id_list_ci[i];
+			msgb_put_u16(msg, id->ci);
+		}
+		break;
+	case CELL_IDENT_LAI_AND_LAC:
+		OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAI_AND_LAC_MAXLEN)
+		for (i = 0; i < cil->id_list_len; i++) {
+			const struct osmo_location_area_id *id = &cil->id_list.id_list_lai_and_lac[i];
+			struct gsm48_loc_area_id lai;
+			gsm48_generate_lai(&lai, id->plmn.mcc, id->plmn.mnc, id->lac);
+			memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai));
+		}
+		break;
 	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 = &cil->id_list.id_list_lac[i];
+			msgb_put_u16(msg, id->lac);
 		}
 		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 */
+		/* Support for other identifier list types is not implemented. */
 		OSMO_ASSERT(false);
 	}
 
 	*tlv_len = (uint8_t) (msg->tail - old_tail);
 	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 osmo_cell_global_id *id_list, unsigned int maxlen, const uint8_t *data,
+				     size_t remain, size_t *consumed)
+{
+	struct osmo_cell_global_id *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->lai.plmn.mcc, &id->lai.plmn.mnc, &id->lai.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->cell_identity = 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 osmo_location_area_id *id_list, unsigned int maxlen,
+				     const uint8_t *data, size_t remain, size_t *consumed)
+{
+	struct osmo_location_area_id *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->plmn.mcc, &id->plmn.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
@@ -615,8 +775,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 +790,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: 6
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Stefan Sperling <ssperling at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Stefan Sperling <ssperling at sysmocom.de>


More information about the gerrit-log mailing list