Change in libosmocore[master]: gsm0808: add BSSMAP Cell Identifier matching API

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/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Mon Oct 29 17:01:23 UTC 2018


Neels Hofmeyr has uploaded this change for review. ( https://gerrit.osmocom.org/11504


Change subject: gsm0808: add BSSMAP Cell Identifier matching API
......................................................................

gsm0808: add BSSMAP Cell Identifier matching API

Add
* osmo_lai_cmp() (to use in gsm0808_cell_id_u_matches())
* osmo_cgi_cmp() (to use in gsm0808_cell_id_u_matches())
* gsm0808_cell_id_u_matches() (to re-use for single IDs and lists)
* gsm0808_cell_ids_match()
* gsm0808_cell_id_matches_list()
* Unit tests in gsm0808_test.c

Rationale:

For inter-BSC handover, it is interesting to find matches between *differing*
Cell Identity kinds. For example, if a cell as CGI 23-42-3-5, and a HO for
LAC-CI 3-5 should be handled, we need to see the match.

This is most interesting for osmo-msc, i.e. to direct the BSSMAP Handover
Request towards the correct BSC -- not yet being implemented ATM though.

It is also interesting for osmo-bsc's VTY interface, to be able to manage
cells' neighbors and to trigger manual handovers by various Cell Identity
handles, as the user would expect them.

Granted, the osmo-bsc VTY UI isn't a really pressing need to be adding this at
this moment, but with the future perspective of osmo-msc also using it, I
preferred to do the UI "properly" as well now.

Change-Id: I5535f0d149c2173294538df75764dd181b023312
---
M include/osmocom/gsm/gsm0808_utils.h
M include/osmocom/gsm/gsm23003.h
M src/gsm/gsm0808_utils.c
M src/gsm/gsm23003.c
M src/gsm/libosmogsm.map
M tests/gsm0808/gsm0808_test.c
M tests/gsm0808/gsm0808_test.ok
7 files changed, 574 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/04/11504/1

diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index f70dbdb..29730c2 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -67,6 +67,12 @@
 int gsm0808_cell_id_list_name_buf(char *buf, size_t buflen, const struct gsm0808_cell_id_list2 *cil);
 int gsm0808_cell_id_u_name(char *buf, size_t buflen,
 			   enum CELL_IDENT id_discr, const union gsm0808_cell_id_u *u);
+bool gsm0808_cell_id_u_matches(enum CELL_IDENT discr1, const union gsm0808_cell_id_u *u1,
+			       enum CELL_IDENT discr2, const union gsm0808_cell_id_u *u2);
+bool gsm0808_cell_ids_match(const struct gsm0808_cell_id *id1, const struct gsm0808_cell_id *id2);
+int gsm0808_cell_id_matches_list(const struct gsm0808_cell_id *id,
+				 const struct gsm0808_cell_id_list2 *list,
+				 unsigned int match_nr);
 
 uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
 				    const struct sockaddr_storage *ss);
diff --git a/include/osmocom/gsm/gsm23003.h b/include/osmocom/gsm/gsm23003.h
index 2f380ae..cb228b7 100644
--- a/include/osmocom/gsm/gsm23003.h
+++ b/include/osmocom/gsm/gsm23003.h
@@ -121,6 +121,8 @@
 
 int osmo_mnc_cmp(uint16_t a_mnc, bool a_mnc_3_digits, uint16_t b_mnc, bool b_mnc_3_digits);
 int osmo_plmn_cmp(const struct osmo_plmn_id *a, const struct osmo_plmn_id *b);
+int osmo_lai_cmp(const struct osmo_location_area_id *a, const struct osmo_location_area_id *b);
+int osmo_cgi_cmp(const struct osmo_cell_global_id *a, const struct osmo_cell_global_id *b);
 
 int osmo_gen_home_network_domain(char *out, const struct osmo_plmn_id *plmn);
 int osmo_parse_home_network_domain(struct osmo_plmn_id *out, const char *in);
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 2348105..147d069 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -1266,6 +1266,146 @@
 	}
 }
 
+/* Store individual Cell Identifier information in a CGI, without clearing the remaining ones.
+ * This is useful to supplement one CGI with information from more than one Cell Identifier,
+ * which in turn is useful to match Cell Identifiers of differing kinds to each other.
+ * Before first invocation, clear the *dst struct externally, this function does only write those members
+ * that are present in parameter u.
+ */
+static void cell_id_to_cgi(struct osmo_cell_global_id *dst,
+			   enum CELL_IDENT discr, const union gsm0808_cell_id_u *u)
+{
+	switch (discr) {
+	case CELL_IDENT_WHOLE_GLOBAL:
+		*dst = u->global;
+		return;
+
+	case CELL_IDENT_LAC_AND_CI:
+		dst->lai.lac = u->lac_and_ci.lac;
+		dst->cell_identity = u->lac_and_ci.ci;
+		return;
+
+	case CELL_IDENT_CI:
+		dst->cell_identity = u->ci;
+		return;
+
+	case CELL_IDENT_LAI_AND_LAC:
+		dst->lai = u->lai_and_lac;
+		return;
+
+	case CELL_IDENT_LAC:
+		dst->lai.lac = u->lac;
+		return;
+
+	case CELL_IDENT_NO_CELL:
+	case CELL_IDENT_BSS:
+	case CELL_IDENT_UTRAN_PLMN_LAC_RNC:
+	case CELL_IDENT_UTRAN_RNC:
+	case CELL_IDENT_UTRAN_LAC_RNC:
+		/* No values to set. */
+		return;
+	}
+}
+
+/*! Return true if the common information between the two Cell Identifiers match.
+ * For example, if a LAC+CI is compared to LAC, return true if the LAC are the same.
+ * Note that CELL_IDENT_NO_CELL will always return false.
+ * Also CELL_IDENT_BSS will always return false, since this function cannot possibly
+ * know the bounds of the BSS, so the caller must handle CELL_IDENT_BSS specially.
+ * \param[in] discr1  Cell Identifier type.
+ * \param[in] u1  Cell Identifier value.
+ * \param[in] discr2  Other Cell Identifier type.
+ * \param[in] u2  Other Cell Identifier value.
+ * \returns True if the common fields of the above match.
+ */
+bool gsm0808_cell_id_u_match(enum CELL_IDENT discr1, const union gsm0808_cell_id_u *u1,
+			     enum CELL_IDENT discr2, const union gsm0808_cell_id_u *u2)
+{
+	struct osmo_cell_global_id a = {};
+	struct osmo_cell_global_id b = {};
+
+	/* First handle the odd wildcard like CELL_IDENT kinds. We can't really match any of these. */
+	switch (discr1) {
+	case CELL_IDENT_NO_CELL:
+	case CELL_IDENT_UTRAN_PLMN_LAC_RNC:
+	case CELL_IDENT_UTRAN_RNC:
+	case CELL_IDENT_UTRAN_LAC_RNC:
+	case CELL_IDENT_BSS:
+		return false;
+	default:
+		break;
+	}
+	switch (discr2) {
+	case CELL_IDENT_NO_CELL:
+	case CELL_IDENT_UTRAN_PLMN_LAC_RNC:
+	case CELL_IDENT_UTRAN_RNC:
+	case CELL_IDENT_UTRAN_LAC_RNC:
+	case CELL_IDENT_BSS:
+		return false;
+	default:
+		break;
+	}
+
+	/* Enrich both sides to full CGI, then compare those. First set the *other* ID's values in case
+	 * they assign more items. For example:
+	 * u1 = LAC:42
+	 * u2 = LAC+CI:23+5
+	 * 1) a <- LAC+CI:23+5
+	 * 2) a <- LAC:42 so that a = LAC+CI:42+5
+	 * Now we can compare those two and find a mismatch. If the LAC were the same, we would get
+	 * identical LAC+CI and hence a match. */
+
+	cell_id_to_cgi(&a, discr2, u2);
+	cell_id_to_cgi(&a, discr1, u1);
+
+	cell_id_to_cgi(&b, discr1, u1);
+	cell_id_to_cgi(&b, discr2, u2);
+
+	return osmo_cgi_cmp(&a, &b) == 0;
+}
+
+/*! Return true if the common information between the two Cell Identifiers match.
+ * For example, if a LAC+CI is compared to LAC, return true if the LAC are the same.
+ * Note that CELL_IDENT_NO_CELL will always return false.
+ * Also CELL_IDENT_BSS will always return false, since this function cannot possibly
+ * know the bounds of the BSS, so the caller must handle CELL_IDENT_BSS specially.
+ * \param[in] id1  Cell Identifier.
+ * \param[in] id2  Other Cell Identifier.
+ * \returns True if the common fields of the above match.
+ */
+bool gsm0808_cell_ids_match(const struct gsm0808_cell_id *id1, const struct gsm0808_cell_id *id2)
+{
+	return gsm0808_cell_id_u_match(id1->id_discr, &id1->id,
+				       id2->id_discr, &id2->id);
+}
+
+/*! Find an index in a Cell Identifier list that matches a given single Cell Identifer.
+ * Compare \a id against each entry in \a list using gsm0808_cell_ids_match(), and return the list index
+ * if a match is found. \a match_nr allows iterating all matches in the list. A match_nr <= 0 returns the
+ * first match in the list, match_nr == 1 the second match, etc., and if match_nr exceeds the available
+ * matches in the list, -1 is returned.
+ * \param[in] id  Cell Identifier to match.
+ * \param[in] list  Cell Identifier list to search in.
+ * \param[in] match_nr  Ignore this many matches.
+ * \returns -1 if no match is found, list index if a match is found.
+ */
+int gsm0808_cell_id_matches_list(const struct gsm0808_cell_id *id,
+				 const struct gsm0808_cell_id_list2 *list,
+				 unsigned int match_nr)
+{
+	int i;
+	for (i = 0; i < list->id_list_len; i++) {
+		if (gsm0808_cell_id_u_match(id->id_discr, &id->id,
+					    list->id_discr, &list->id_list[i])) {
+			if (match_nr)
+				match_nr --;
+			else
+				return i;
+		}
+	}
+	return -1;
+}
+
 /*! value_string[] for enum CELL_IDENT. */
 const struct value_string gsm0808_cell_id_discr_names[] = {
 	{ CELL_IDENT_WHOLE_GLOBAL, "CGI" },
diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c
index 4fdad48..6abda41 100644
--- a/src/gsm/gsm23003.c
+++ b/src/gsm/gsm23003.c
@@ -306,6 +306,40 @@
 	return osmo_mnc_cmp(a->mnc, a->mnc_3_digits, b->mnc, b->mnc_3_digits);
 }
 
+/* Compare two LAI.
+ * The order of comparison is MCC, MNC, LAC. See also osmo_plmn_cmp().
+ * \param a[in]  "Left" side LAI.
+ * \param b[in]  "Right" side LAI.
+ * \returns 0 if the LAI are equal, -1 if a < b, 1 if a > b. */
+int osmo_lai_cmp(const struct osmo_location_area_id *a, const struct osmo_location_area_id *b)
+{
+	int rc = osmo_plmn_cmp(&a->plmn, &b->plmn);
+	if (rc)
+		return rc;
+	if (a->lac < b->lac)
+		return -1;
+	if (a->lac > b->lac)
+		return 1;
+	return 0;
+}
+
+/* Compare two CGI.
+ * The order of comparison is MCC, MNC, LAC, CI. See also osmo_lai_cmp().
+ * \param a[in]  "Left" side CGI.
+ * \param b[in]  "Right" side CGI.
+ * \returns 0 if the CGI are equal, -1 if a < b, 1 if a > b. */
+int osmo_cgi_cmp(const struct osmo_cell_global_id *a, const struct osmo_cell_global_id *b)
+{
+	int rc = osmo_lai_cmp(&a->lai, &b->lai);
+	if (rc)
+		return rc;
+	if (a->cell_identity < b->cell_identity)
+		return -1;
+	if (a->cell_identity > b->cell_identity)
+		return 1;
+	return 0;
+}
+
 /*! Generate TS 23.003 Section 19.2 Home Network Realm/Domain (text form)
  *  \param out[out] caller-provided output buffer, at least 33 bytes long
  *  \param plmn[in] Osmocom representation of PLMN ID (MCC + MNC)
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 4813e13..ecc368e 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -203,6 +203,9 @@
 gsm0808_cell_id_list_name_buf;
 gsm0808_cell_id_discr_names;
 gsm0808_cell_id_u_name;
+gsm0808_cell_id_u_matches;
+gsm0808_cell_ids_match;
+gsm0808_cell_id_matches_list;
 gsm0808_chan_type_to_speech_codec;
 gsm0808_speech_codec_from_chan_type;
 gsm0808_sc_cfg_from_gsm48_mr_cfg;
diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c
index 0b2794f..7f121aa 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -1718,6 +1718,270 @@
 	    (GSM0808_SC_CFG_DEFAULT_AMR_7_95 | GSM0808_SC_CFG_DEFAULT_AMR_12_2);
 }
 
+struct test_cell_id_matching_data {
+	struct gsm0808_cell_id id;
+	struct gsm0808_cell_id match_id;
+	bool expect_match;
+};
+
+const struct gsm0808_cell_id lac_23 = { .id_discr = CELL_IDENT_LAC, .id.lac = 23, };
+const struct gsm0808_cell_id lac_42 = { .id_discr = CELL_IDENT_LAC, .id.lac = 42, };
+const struct gsm0808_cell_id ci_5 = { .id_discr = CELL_IDENT_CI, .id.ci = 5, };
+const struct gsm0808_cell_id ci_6 = { .id_discr = CELL_IDENT_CI, .id.ci = 6, };
+const struct gsm0808_cell_id lac_ci_23_5 = {
+		.id_discr = CELL_IDENT_LAC_AND_CI,
+		.id.lac_and_ci = { .lac = 23, .ci = 5, },
+	};
+const struct gsm0808_cell_id lac_ci_42_6 = {
+		.id_discr = CELL_IDENT_LAC_AND_CI,
+		.id.lac_and_ci = { .lac = 42, .ci = 6, },
+	};
+const struct gsm0808_cell_id lai_23_042_23 = {
+		.id_discr = CELL_IDENT_LAI_AND_LAC,
+		.id.lai_and_lac = { .plmn = { .mcc = 23, .mnc = 42, .mnc_3_digits = true }, .lac = 23, },
+	};
+const struct gsm0808_cell_id lai_23_042_42 = {
+		.id_discr = CELL_IDENT_LAI_AND_LAC,
+		.id.lai_and_lac = { .plmn = { .mcc = 23, .mnc = 42, .mnc_3_digits = true }, .lac = 42, },
+	};
+const struct gsm0808_cell_id lai_23_99_23 = {
+		.id_discr = CELL_IDENT_LAI_AND_LAC,
+		.id.lai_and_lac = { .plmn = { .mcc = 23, .mnc = 99, .mnc_3_digits = false }, .lac = 23, },
+	};
+const struct gsm0808_cell_id lai_23_42_23 = {
+		.id_discr = CELL_IDENT_LAI_AND_LAC,
+		.id.lai_and_lac = { .plmn = { .mcc = 23, .mnc = 42, .mnc_3_digits = false }, .lac = 23, },
+	};
+const struct gsm0808_cell_id cgi_23_042_23_5 = {
+		.id_discr = CELL_IDENT_WHOLE_GLOBAL,
+		.id.global = {
+			.lai = { .plmn = { .mcc = 23, .mnc = 42, .mnc_3_digits = true }, .lac = 23, },
+			.cell_identity = 5,
+		},
+	};
+const struct gsm0808_cell_id cgi_23_042_42_6 = {
+		.id_discr = CELL_IDENT_WHOLE_GLOBAL,
+		.id.global = {
+			.lai = { .plmn = { .mcc = 23, .mnc = 42, .mnc_3_digits = true }, .lac = 42, },
+			.cell_identity = 6,
+		},
+	};
+const struct gsm0808_cell_id cgi_23_99_23_5 = {
+		.id_discr = CELL_IDENT_WHOLE_GLOBAL,
+		.id.global = {
+			.lai = { .plmn = { .mcc = 23, .mnc = 99, .mnc_3_digits = false }, .lac = 23, },
+			.cell_identity = 5,
+		},
+	};
+
+
+const struct test_cell_id_matching_data test_cell_id_matching_tests[] = {
+	{ .id = lac_23, .match_id = lac_23, .expect_match = true },
+	{ .id = lac_23, .match_id = lac_42, .expect_match = false },
+	{ .id = lac_23, .match_id = ci_5, .expect_match = true },
+	{ .id = lac_23, .match_id = ci_6, .expect_match = true },
+	{ .id = lac_23, .match_id = lac_ci_23_5, .expect_match = true },
+	{ .id = lac_23, .match_id = lac_ci_42_6, .expect_match = false },
+	{ .id = lac_23, .match_id = lai_23_042_23, .expect_match = true },
+	{ .id = lac_23, .match_id = lai_23_042_42, .expect_match = false },
+	{ .id = lac_23, .match_id = lai_23_99_23, .expect_match = true },
+	{ .id = lac_23, .match_id = lai_23_42_23, .expect_match = true },
+	{ .id = lac_23, .match_id = cgi_23_042_23_5, .expect_match = true },
+	{ .id = lac_23, .match_id = cgi_23_042_42_6, .expect_match = false },
+	{ .id = lac_23, .match_id = cgi_23_99_23_5, .expect_match = true },
+	{ .id = ci_5, .match_id = lac_23, .expect_match = true },
+	{ .id = ci_5, .match_id = lac_42, .expect_match = true },
+	{ .id = ci_5, .match_id = ci_5, .expect_match = true },
+	{ .id = ci_5, .match_id = ci_6, .expect_match = false },
+	{ .id = ci_5, .match_id = lac_ci_23_5, .expect_match = true },
+	{ .id = ci_5, .match_id = lac_ci_42_6, .expect_match = false },
+	{ .id = ci_5, .match_id = lai_23_042_23, .expect_match = true },
+	{ .id = ci_5, .match_id = lai_23_042_42, .expect_match = true },
+	{ .id = ci_5, .match_id = lai_23_99_23, .expect_match = true },
+	{ .id = ci_5, .match_id = lai_23_42_23, .expect_match = true },
+	{ .id = ci_5, .match_id = cgi_23_042_23_5, .expect_match = true },
+	{ .id = ci_5, .match_id = cgi_23_042_42_6, .expect_match = false },
+	{ .id = ci_5, .match_id = cgi_23_99_23_5, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = lac_23, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = lac_42, .expect_match = false },
+	{ .id = lac_ci_23_5, .match_id = ci_5, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = ci_6, .expect_match = false },
+	{ .id = lac_ci_23_5, .match_id = lac_ci_23_5, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = lac_ci_42_6, .expect_match = false },
+	{ .id = lac_ci_23_5, .match_id = lai_23_042_23, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = lai_23_042_42, .expect_match = false },
+	{ .id = lac_ci_23_5, .match_id = lai_23_99_23, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = lai_23_42_23, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = cgi_23_042_23_5, .expect_match = true },
+	{ .id = lac_ci_23_5, .match_id = cgi_23_042_42_6, .expect_match = false },
+	{ .id = lac_ci_23_5, .match_id = cgi_23_99_23_5, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = lac_23, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = lac_42, .expect_match = false },
+	{ .id = lai_23_042_23, .match_id = ci_5, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = ci_6, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = lac_ci_23_5, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = lac_ci_42_6, .expect_match = false },
+	{ .id = lai_23_042_23, .match_id = lai_23_042_23, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = lai_23_042_42, .expect_match = false },
+	{ .id = lai_23_042_23, .match_id = lai_23_99_23, .expect_match = false },
+	{ .id = lai_23_042_23, .match_id = lai_23_42_23, .expect_match = false },
+	{ .id = lai_23_042_23, .match_id = cgi_23_042_23_5, .expect_match = true },
+	{ .id = lai_23_042_23, .match_id = cgi_23_042_42_6, .expect_match = false },
+	{ .id = lai_23_042_23, .match_id = cgi_23_99_23_5, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = lac_23, .expect_match = true },
+	{ .id = cgi_23_042_23_5, .match_id = lac_42, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = ci_5, .expect_match = true },
+	{ .id = cgi_23_042_23_5, .match_id = ci_6, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = lac_ci_23_5, .expect_match = true },
+	{ .id = cgi_23_042_23_5, .match_id = lac_ci_42_6, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = lai_23_042_23, .expect_match = true },
+	{ .id = cgi_23_042_23_5, .match_id = lai_23_042_42, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = lai_23_99_23, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = lai_23_42_23, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = cgi_23_042_23_5, .expect_match = true },
+	{ .id = cgi_23_042_23_5, .match_id = cgi_23_042_42_6, .expect_match = false },
+	{ .id = cgi_23_042_23_5, .match_id = cgi_23_99_23_5, .expect_match = false },
+};
+
+
+static void test_cell_id_matching()
+{
+	int i;
+	bool ok = true;
+	printf("\n%s\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(test_cell_id_matching_tests); i++) {
+		const struct test_cell_id_matching_data *d = &test_cell_id_matching_tests[i];
+		bool result;
+
+		result = gsm0808_cell_ids_match(&d->id, &d->match_id);
+
+		printf("[%d] %s %s %s\n",
+		       i,
+		       gsm0808_cell_id_name(&d->id),
+		       gsm0808_cell_id_name2(&d->match_id),
+		       result ? "MATCH" : "don't match");
+		if (result != d->expect_match) {
+			printf("  ERROR: expected %s\n", d->expect_match ? "MATCH" : "no match");
+			ok = false;
+		}
+	}
+
+	OSMO_ASSERT(ok);
+}
+
+static bool test_cell_id_list_matching_discrs(bool test_match,
+					      enum CELL_IDENT id_discr,
+					      enum CELL_IDENT list_discr)
+{
+	int i, j;
+	const struct gsm0808_cell_id *id = NULL;
+	struct gsm0808_cell_id_list2 list = {};
+	int match_idx = -1;
+	int result;
+
+	for (i = 0; i < ARRAY_SIZE(test_cell_id_matching_tests); i++) {
+		const struct test_cell_id_matching_data *d = &test_cell_id_matching_tests[i];
+		if (id_discr != d->id.id_discr)
+			continue;
+		id = &d->id;
+		break;
+	}
+
+	if (!id) {
+		printf("Did not find any entry for %s\n", gsm0808_cell_id_discr_name(id_discr));
+		return true;
+	}
+
+	/* Collect those entries with exactly this id on the left, of type list_discr on the right.
+	 * Collect the mismatches first, for more interesting match indexes in the results. */
+	for (j = 0; j < 2; j++) {
+		bool collect_matches = (bool)j;
+
+		/* If we want to have a mismatching list, don't add any entries that match. */
+		if (!test_match && collect_matches)
+			continue;
+
+		for (i = 0; i < ARRAY_SIZE(test_cell_id_matching_tests); i++) {
+			const struct test_cell_id_matching_data *d = &test_cell_id_matching_tests[i];
+			struct gsm0808_cell_id_list2 add;
+
+			/* Ignore those with a different d->id */
+			if (d->id.id_discr != id->id_discr
+			    || !gsm0808_cell_ids_match(&d->id, id))
+				continue;
+
+			/* Ignore those with a different d->match_id discr */
+			if (d->match_id.id_discr != list_discr)
+				continue;
+
+			if (collect_matches != d->expect_match)
+				continue;
+
+			if (match_idx < 0 && d->expect_match) {
+				match_idx = list.id_list_len;
+			}
+
+			gsm0808_cell_id_to_list(&add, &d->match_id);
+			gsm0808_cell_id_list_add(&list, &add);
+		}
+	}
+
+	if (!list.id_list_len) {
+		printf("%s vs. %s: No match_id entries to test %s\n",
+		       gsm0808_cell_id_name(id),
+		       gsm0808_cell_id_discr_name(list_discr),
+		       test_match ? "MATCH" : "mismatch");
+		return true;
+	}
+
+	result = gsm0808_cell_id_matches_list(id, &list, 0);
+
+	printf("%s and %s: ",
+	       gsm0808_cell_id_name(id),
+	       gsm0808_cell_id_list_name(&list));
+	if (result >= 0)
+		printf("MATCH at [%d]\n", result);
+	else
+		printf("mismatch\n");
+
+	if (test_match
+	    && (result < 0 || result != match_idx)) {
+		printf("  ERROR: expected MATCH at %d\n", match_idx);
+		return false;
+	}
+
+	if (!test_match && result >= 0) {
+		printf("  ERROR: expected mismatch\n");
+		return false;
+	}
+
+	return true;
+}
+
+static void test_cell_id_list_matching(bool test_match)
+{
+	int i, j;
+	bool ok = true;
+
+	const enum CELL_IDENT discrs[] = {
+		CELL_IDENT_LAC, CELL_IDENT_CI, CELL_IDENT_LAC_AND_CI, CELL_IDENT_LAI_AND_LAC,
+		CELL_IDENT_WHOLE_GLOBAL,
+	};
+
+	printf("\n%s(%s)\n", __func__, test_match ? "test match" : "test mismatch");
+
+	/* Autogenerate Cell ID lists from above dataset, which should match / not match. */
+	for (i = 0; i < ARRAY_SIZE(discrs); i++) {
+		for (j = 0; j < ARRAY_SIZE(discrs); j++)
+			if (!test_cell_id_list_matching_discrs(test_match,
+							       discrs[i], discrs[j]))
+				ok = false;
+	}
+
+	OSMO_ASSERT(ok);
+}
+
 int main(int argc, char **argv)
 {
 	printf("Testing generation of GSM0808 messages\n");
@@ -1773,6 +2037,10 @@
 	test_gsm0808_sc_cfg_from_gsm48_mr_cfg();
 	test_gsm48_mr_cfg_from_gsm0808_sc_cfg();
 
+	test_cell_id_matching();
+	test_cell_id_list_matching(true);
+	test_cell_id_list_matching(false);
+
 	printf("Done\n");
 	return EXIT_SUCCESS;
 }
diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok
index 58bc509..9ee54df 100644
--- a/tests/gsm0808/gsm0808_test.ok
+++ b/tests/gsm0808/gsm0808_test.ok
@@ -432,4 +432,125 @@
  m10_2= 0
  m12_2= 1
 
+
+test_cell_id_matching
+[0] LAC:23 LAC:23 MATCH
+[1] LAC:23 LAC:42 don't match
+[2] LAC:23 CI:5 MATCH
+[3] LAC:23 CI:6 MATCH
+[4] LAC:23 LAC-CI:23-5 MATCH
+[5] LAC:23 LAC-CI:42-6 don't match
+[6] LAC:23 LAI:023-042-23 MATCH
+[7] LAC:23 LAI:023-042-42 don't match
+[8] LAC:23 LAI:023-99-23 MATCH
+[9] LAC:23 LAI:023-42-23 MATCH
+[10] LAC:23 CGI:023-042-23-5 MATCH
+[11] LAC:23 CGI:023-042-42-6 don't match
+[12] LAC:23 CGI:023-99-23-5 MATCH
+[13] CI:5 LAC:23 MATCH
+[14] CI:5 LAC:42 MATCH
+[15] CI:5 CI:5 MATCH
+[16] CI:5 CI:6 don't match
+[17] CI:5 LAC-CI:23-5 MATCH
+[18] CI:5 LAC-CI:42-6 don't match
+[19] CI:5 LAI:023-042-23 MATCH
+[20] CI:5 LAI:023-042-42 MATCH
+[21] CI:5 LAI:023-99-23 MATCH
+[22] CI:5 LAI:023-42-23 MATCH
+[23] CI:5 CGI:023-042-23-5 MATCH
+[24] CI:5 CGI:023-042-42-6 don't match
+[25] CI:5 CGI:023-99-23-5 MATCH
+[26] LAC-CI:23-5 LAC:23 MATCH
+[27] LAC-CI:23-5 LAC:42 don't match
+[28] LAC-CI:23-5 CI:5 MATCH
+[29] LAC-CI:23-5 CI:6 don't match
+[30] LAC-CI:23-5 LAC-CI:23-5 MATCH
+[31] LAC-CI:23-5 LAC-CI:42-6 don't match
+[32] LAC-CI:23-5 LAI:023-042-23 MATCH
+[33] LAC-CI:23-5 LAI:023-042-42 don't match
+[34] LAC-CI:23-5 LAI:023-99-23 MATCH
+[35] LAC-CI:23-5 LAI:023-42-23 MATCH
+[36] LAC-CI:23-5 CGI:023-042-23-5 MATCH
+[37] LAC-CI:23-5 CGI:023-042-42-6 don't match
+[38] LAC-CI:23-5 CGI:023-99-23-5 MATCH
+[39] LAI:023-042-23 LAC:23 MATCH
+[40] LAI:023-042-23 LAC:42 don't match
+[41] LAI:023-042-23 CI:5 MATCH
+[42] LAI:023-042-23 CI:6 MATCH
+[43] LAI:023-042-23 LAC-CI:23-5 MATCH
+[44] LAI:023-042-23 LAC-CI:42-6 don't match
+[45] LAI:023-042-23 LAI:023-042-23 MATCH
+[46] LAI:023-042-23 LAI:023-042-42 don't match
+[47] LAI:023-042-23 LAI:023-99-23 don't match
+[48] LAI:023-042-23 LAI:023-42-23 don't match
+[49] LAI:023-042-23 CGI:023-042-23-5 MATCH
+[50] LAI:023-042-23 CGI:023-042-42-6 don't match
+[51] LAI:023-042-23 CGI:023-99-23-5 don't match
+[52] CGI:023-042-23-5 LAC:23 MATCH
+[53] CGI:023-042-23-5 LAC:42 don't match
+[54] CGI:023-042-23-5 CI:5 MATCH
+[55] CGI:023-042-23-5 CI:6 don't match
+[56] CGI:023-042-23-5 LAC-CI:23-5 MATCH
+[57] CGI:023-042-23-5 LAC-CI:42-6 don't match
+[58] CGI:023-042-23-5 LAI:023-042-23 MATCH
+[59] CGI:023-042-23-5 LAI:023-042-42 don't match
+[60] CGI:023-042-23-5 LAI:023-99-23 don't match
+[61] CGI:023-042-23-5 LAI:023-42-23 don't match
+[62] CGI:023-042-23-5 CGI:023-042-23-5 MATCH
+[63] CGI:023-042-23-5 CGI:023-042-42-6 don't match
+[64] CGI:023-042-23-5 CGI:023-99-23-5 don't match
+
+test_cell_id_list_matching(test match)
+LAC:23 and LAC[2]:{42, 23}: MATCH at [1]
+LAC:23 and CI[2]:{5, 6}: MATCH at [0]
+LAC:23 and LAC-CI[2]:{42-6, 23-5}: MATCH at [1]
+LAC:23 and LAI[4]:{023-042-42, 023-042-23, 023-99-23, 023-42-23}: MATCH at [1]
+LAC:23 and CGI[3]:{023-042-42-6, 023-042-23-5, 023-99-23-5}: MATCH at [1]
+CI:5 and LAC[2]:{23, 42}: MATCH at [0]
+CI:5 and CI[2]:{6, 5}: MATCH at [1]
+CI:5 and LAC-CI[2]:{42-6, 23-5}: MATCH at [1]
+CI:5 and LAI[4]:{023-042-23, 023-042-42, 023-99-23, 023-42-23}: MATCH at [0]
+CI:5 and CGI[3]:{023-042-42-6, 023-042-23-5, 023-99-23-5}: MATCH at [1]
+LAC-CI:23-5 and LAC[2]:{42, 23}: MATCH at [1]
+LAC-CI:23-5 and CI[2]:{6, 5}: MATCH at [1]
+LAC-CI:23-5 and LAC-CI[2]:{42-6, 23-5}: MATCH at [1]
+LAC-CI:23-5 and LAI[4]:{023-042-42, 023-042-23, 023-99-23, 023-42-23}: MATCH at [1]
+LAC-CI:23-5 and CGI[3]:{023-042-42-6, 023-042-23-5, 023-99-23-5}: MATCH at [1]
+LAI:023-042-23 and LAC[2]:{42, 23}: MATCH at [1]
+LAI:023-042-23 and CI[2]:{5, 6}: MATCH at [0]
+LAI:023-042-23 and LAC-CI[2]:{42-6, 23-5}: MATCH at [1]
+LAI:023-042-23 and LAI[4]:{023-042-42, 023-99-23, 023-42-23, 023-042-23}: MATCH at [3]
+LAI:023-042-23 and CGI[3]:{023-042-42-6, 023-99-23-5, 023-042-23-5}: MATCH at [2]
+CGI:023-042-23-5 and LAC[2]:{42, 23}: MATCH at [1]
+CGI:023-042-23-5 and CI[2]:{6, 5}: MATCH at [1]
+CGI:023-042-23-5 and LAC-CI[2]:{42-6, 23-5}: MATCH at [1]
+CGI:023-042-23-5 and LAI[4]:{023-042-42, 023-99-23, 023-42-23, 023-042-23}: MATCH at [3]
+CGI:023-042-23-5 and CGI[3]:{023-042-42-6, 023-99-23-5, 023-042-23-5}: MATCH at [2]
+
+test_cell_id_list_matching(test mismatch)
+LAC:23 and LAC[1]:{42}: mismatch
+LAC:23 vs. CI: No match_id entries to test mismatch
+LAC:23 and LAC-CI[1]:{42-6}: mismatch
+LAC:23 and LAI[1]:{023-042-42}: mismatch
+LAC:23 and CGI[1]:{023-042-42-6}: mismatch
+CI:5 vs. LAC: No match_id entries to test mismatch
+CI:5 and CI[1]:{6}: mismatch
+CI:5 and LAC-CI[1]:{42-6}: mismatch
+CI:5 vs. LAI: No match_id entries to test mismatch
+CI:5 and CGI[1]:{023-042-42-6}: mismatch
+LAC-CI:23-5 and LAC[1]:{42}: mismatch
+LAC-CI:23-5 and CI[1]:{6}: mismatch
+LAC-CI:23-5 and LAC-CI[1]:{42-6}: mismatch
+LAC-CI:23-5 and LAI[1]:{023-042-42}: mismatch
+LAC-CI:23-5 and CGI[1]:{023-042-42-6}: mismatch
+LAI:023-042-23 and LAC[1]:{42}: mismatch
+LAI:023-042-23 vs. CI: No match_id entries to test mismatch
+LAI:023-042-23 and LAC-CI[1]:{42-6}: mismatch
+LAI:023-042-23 and LAI[3]:{023-042-42, 023-99-23, 023-42-23}: mismatch
+LAI:023-042-23 and CGI[2]:{023-042-42-6, 023-99-23-5}: mismatch
+CGI:023-042-23-5 and LAC[1]:{42}: mismatch
+CGI:023-042-23-5 and CI[1]:{6}: mismatch
+CGI:023-042-23-5 and LAC-CI[1]:{42-6}: mismatch
+CGI:023-042-23-5 and LAI[3]:{023-042-42, 023-99-23, 023-42-23}: mismatch
+CGI:023-042-23-5 and CGI[2]:{023-042-42-6, 023-99-23-5}: mismatch
 Done

-- 
To view, visit https://gerrit.osmocom.org/11504
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5535f0d149c2173294538df75764dd181b023312
Gerrit-Change-Number: 11504
Gerrit-PatchSet: 1
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20181029/a7566a2c/attachment.htm>


More information about the gerrit-log mailing list