summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gsm/gsm0808_utils.h1
-rw-r--r--src/gsm/gsm0808_utils.c79
-rw-r--r--src/gsm/libosmogsm.map1
-rw-r--r--tests/gsm0808/gsm0808_test.c195
-rw-r--r--tests/gsm0808/gsm0808_test.ok85
5 files changed, 361 insertions, 0 deletions
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index 363fc390..34eae438 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -77,6 +77,7 @@ int gsm0808_dec_cell_id_list2(struct gsm0808_cell_id_list2 *cil, const uint8_t *
int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
const uint8_t *elem, uint8_t len)
OSMO_DEPRECATED("use gsm0808_dec_cell_id_list2 instead");
+int gsm0808_cell_id_list_add(struct gsm0808_cell_id_list2 *dst, const struct gsm0808_cell_id_list2 *src);
int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch);
int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
uint8_t perm_spch);
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index e4872b87..996456e1 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -909,6 +909,85 @@ int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
return (int)(elem - old_elem);
}
+static bool same_cell_id_list_entries(const struct gsm0808_cell_id_list2 *a, int ai,
+ const struct gsm0808_cell_id_list2 *b, int bi)
+{
+ struct gsm0808_cell_id_list2 tmp = {
+ .id_discr = a->id_discr,
+ .id_list_len = 1,
+ };
+ uint8_t buf_a[32 + sizeof(struct msgb)];
+ uint8_t buf_b[32 + sizeof(struct msgb)];
+ struct msgb *msg_a = (void*)buf_a;
+ struct msgb *msg_b = (void*)buf_b;
+
+ msg_a->data_len = 32;
+ msg_b->data_len = 32;
+ msgb_reset(msg_a);
+ msgb_reset(msg_b);
+
+ if (a->id_discr != b->id_discr)
+ return false;
+ if (ai >= a->id_list_len
+ || bi >= b->id_list_len)
+ return false;
+
+ tmp.id_list[0] = a->id_list[ai];
+ gsm0808_enc_cell_id_list2(msg_a, &tmp);
+
+ tmp.id_list[0] = b->id_list[bi];
+ gsm0808_enc_cell_id_list2(msg_b, &tmp);
+
+ if (msg_a->len != msg_b->len)
+ return false;
+ if (memcmp(msg_a->data, msg_b->data, msg_a->len))
+ return false;
+
+ return true;
+}
+
+/*! Append entries from one Cell Identifier List to another.
+ * The cell identifier types must be identical between the two lists.
+ * \param dst[out] Append entries to this list.
+ * \param src[in] Append these entries to \a dst.
+ * \returns the nr of items added, or negative on error: -EINVAL if the id_discr mismatch
+ * between the lists, -ENOSPC if the destination list does not have enough space. If an error is
+ * returned, \a dst may have already been changed (particularly on -ENOSPC). Note that a return value
+ * of zero may occur when the src->id_list_len is zero, or when all entries from \a src already exist
+ * in \a dst, and does not indicate error per se. */
+int gsm0808_cell_id_list_add(struct gsm0808_cell_id_list2 *dst, const struct gsm0808_cell_id_list2 *src)
+{
+ int i, j;
+ int added = 0;
+
+ if (dst->id_list_len == 0
+ && dst->id_discr != CELL_IDENT_BSS)
+ dst->id_discr = src->id_discr;
+ else if (dst->id_discr != src->id_discr)
+ return -EINVAL;
+
+ for (i = 0; i < src->id_list_len; i++) {
+ /* don't add duplicate entries */
+ bool skip = false;
+ for (j = 0; j < dst->id_list_len; j++) {
+ if (same_cell_id_list_entries(dst, j, src, i)) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+
+ if (dst->id_list_len >= ARRAY_SIZE(dst->id_list))
+ return -ENOSPC;
+
+ dst->id_list[dst->id_list_len++] = src->id_list[i];
+ added ++;
+ }
+
+ return added;
+}
+
/*! Convert the representation of the permitted speech codec identifier
* that is used in struct gsm0808_channel_type to the speech codec
* representation we use in struct gsm0808_speech_codec.
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index a6ea47dd..d99121e2 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -176,6 +176,7 @@ gsm0808_enc_cell_id_list;
gsm0808_enc_cell_id_list2;
gsm0808_dec_cell_id_list;
gsm0808_dec_cell_id_list2;
+gsm0808_cell_id_list_add;
gsm0808_chan_type_to_speech_codec;
gsm0808_speech_codec_from_chan_type;
gsm0808_speech_codec_type_names;
diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c
index 9730be2d..f4670996 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -28,6 +28,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <errno.h>
#define VERIFY(msg, data, len) \
if (msgb_l3len(msg) != len) { \
@@ -1063,6 +1064,198 @@ static void test_gsm0808_enc_dec_cell_id_list_multi_global()
msgb_free(msg);
}
+static void print_cil(const struct gsm0808_cell_id_list2 *cil)
+{
+ unsigned int i;
+ if (!cil) {
+ printf(" cell_id_list == NULL\n");
+ return;
+ }
+ switch (cil->id_discr) {
+ case CELL_IDENT_WHOLE_GLOBAL:
+ printf(" cell_id_list cgi[%u] = {\n", cil->id_list_len);
+ for (i = 0; i < cil->id_list_len; i++)
+ printf(" %2d: %s\n", i, osmo_cgi_name(&cil->id_list[i].global));
+ printf(" }\n");
+ break;
+ case CELL_IDENT_LAC:
+ printf(" cell_id_list lac[%u] = {\n", cil->id_list_len);
+ for (i = 0; i < cil->id_list_len; i++)
+ printf(" %2d: %u\n", i, cil->id_list[i].lac);
+ printf(" }\n");
+ break;
+ case CELL_IDENT_BSS:
+ printf(" cell_id_list bss[%u]\n", cil->id_list_len);
+ break;
+ case CELL_IDENT_NO_CELL:
+ printf(" cell_id_list no_cell[%u]\n", cil->id_list_len);
+ break;
+ default:
+ printf(" Unimplemented id_disc\n");
+ }
+}
+
+void test_cell_id_list_add() {
+ const struct gsm0808_cell_id_list2 cgi1 = {
+ .id_discr = CELL_IDENT_WHOLE_GLOBAL,
+ .id_list_len = 1,
+ .id_list = {
+ {
+ .global = {
+ .lai = {
+ .plmn = { .mcc = 1, .mnc = 2, .mnc_3_digits = false },
+ .lac = 3,
+ },
+ .cell_identity = 4,
+ }
+ },
+ },
+ };
+
+ const struct gsm0808_cell_id_list2 cgi2 = {
+ .id_discr = CELL_IDENT_WHOLE_GLOBAL,
+ .id_list_len = 2,
+ .id_list = {
+ {
+ .global = {
+ .lai = {
+ .plmn = { .mcc = 1, .mnc = 2, .mnc_3_digits = true },
+ .lac = 3,
+ },
+ .cell_identity = 4,
+ }
+ },
+ {
+ .global = {
+ .lai = {
+ .plmn = { .mcc = 5, .mnc = 6, .mnc_3_digits = true },
+ .lac = 7,
+ },
+ .cell_identity = 8,
+ }
+ },
+ },
+ };
+
+ const struct gsm0808_cell_id_list2 cgi2a = {
+ .id_discr = CELL_IDENT_WHOLE_GLOBAL,
+ .id_list_len = 2,
+ .id_list = {
+ {
+ .global = cgi2.id_list[0].global
+ },
+ {
+ .global = {
+ .lai = {
+ .plmn = { .mcc = 9, .mnc = 10, .mnc_3_digits = true },
+ .lac = 11,
+ },
+ .cell_identity = 12,
+ }
+ },
+ },
+ };
+
+ const struct gsm0808_cell_id_list2 cgi3 = {
+ .id_discr = CELL_IDENT_WHOLE_GLOBAL,
+ .id_list_len = 2,
+ .id_list = {
+ {
+ .global = {
+ .lai = {
+ .plmn = { .mcc = 13, .mnc = 14, .mnc_3_digits = true },
+ .lac = 15,
+ },
+ .cell_identity = 16,
+ }
+ },
+ {
+ .global = {
+ .lai = {
+ .plmn = { .mcc = 16, .mnc = 17, .mnc_3_digits = true },
+ .lac = 18,
+ },
+ .cell_identity = 19,
+ }
+ },
+ },
+ };
+
+
+ const struct gsm0808_cell_id_list2 lac1 = {
+ .id_discr = CELL_IDENT_LAC,
+ .id_list_len = 1,
+ .id_list = {
+ {
+ .lac = 123
+ },
+ },
+ };
+
+ const struct gsm0808_cell_id_list2 lac2 = {
+ .id_discr = CELL_IDENT_LAC,
+ .id_list_len = 2,
+ .id_list = {
+ {
+ .lac = 456
+ },
+ {
+ .lac = 789
+ },
+ },
+ };
+
+ struct gsm0808_cell_id_list2 cil = {};
+
+ printf("------- %s\n", __func__);
+
+ print_cil(&cil);
+
+#define ADD_QUIET(other_cil, expect_rc) do { \
+ int rc = gsm0808_cell_id_list_add(&cil, &other_cil); \
+ printf("\ngsm0808_cell_id_list_add(&cil, &" #other_cil ") --> rc = %d\n", rc); \
+ OSMO_ASSERT(rc == expect_rc); \
+ } while(0)
+
+#define ADD(other_cil, expect_rc) ADD_QUIET(other_cil, expect_rc); print_cil(&cil)
+
+ ADD(lac1, 1);
+ ADD(lac1, 0);
+ ADD(lac2, 2);
+ ADD(lac2, 0);
+ ADD(cil, 0);
+ ADD(cgi1, -EINVAL);
+
+ printf("\ncan't add to BSS list\n");
+ cil.id_list_len = 0;
+ cil.id_discr = CELL_IDENT_BSS;
+ print_cil(&cil);
+ ADD(lac1, -EINVAL);
+
+ printf("\nother types (including NO_CELL) take on new type iff empty\n");
+ cil.id_list_len = 0;
+ cil.id_discr = CELL_IDENT_NO_CELL;
+ print_cil(&cil);
+ ADD(cgi1, 1);
+ ADD(cgi1, 0);
+ ADD(cgi2, 2);
+ ADD(cgi2, 0);
+
+ cil.id_list_len = GSM0808_CELL_ID_LIST2_MAXLEN - 1;
+ printf("\ncil.id_list_len = %u", cil.id_list_len);
+ ADD_QUIET(cgi2a, 1);
+ printf("cil.id_list_len = %u\n", cil.id_list_len);
+
+ cil.id_list_len = GSM0808_CELL_ID_LIST2_MAXLEN - 1;
+ printf("\ncil.id_list_len = %u", cil.id_list_len);
+ ADD_QUIET(cgi3, -ENOSPC);
+ printf("cil.id_list_len = %u", cil.id_list_len);
+ ADD_QUIET(cgi2a, -ENOSPC);
+ printf("cil.id_list_len = %u\n", cil.id_list_len);
+
+ printf("------- %s done\n", __func__);
+}
+
int main(int argc, char **argv)
{
printf("Testing generation of GSM0808 messages\n");
@@ -1103,6 +1296,8 @@ int main(int argc, char **argv)
test_gsm0808_enc_dec_cell_id_list_multi_lac_and_ci();
test_gsm0808_enc_dec_cell_id_list_multi_global();
+ test_cell_id_list_add();
+
printf("Done\n");
return EXIT_SUCCESS;
}
diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok
index e101d657..a049dec5 100644
--- a/tests/gsm0808/gsm0808_test.ok
+++ b/tests/gsm0808/gsm0808_test.ok
@@ -19,4 +19,89 @@ Testing creating Clear Request
Testing creating Paging Request
Testing creating DTAP
Testing prepend DTAP
+------- test_cell_id_list_add
+ cell_id_list cgi[0] = {
+ }
+
+gsm0808_cell_id_list_add(&cil, &lac1) --> rc = 1
+ cell_id_list lac[1] = {
+ 0: 123
+ }
+
+gsm0808_cell_id_list_add(&cil, &lac1) --> rc = 0
+ cell_id_list lac[1] = {
+ 0: 123
+ }
+
+gsm0808_cell_id_list_add(&cil, &lac2) --> rc = 2
+ cell_id_list lac[3] = {
+ 0: 123
+ 1: 456
+ 2: 789
+ }
+
+gsm0808_cell_id_list_add(&cil, &lac2) --> rc = 0
+ cell_id_list lac[3] = {
+ 0: 123
+ 1: 456
+ 2: 789
+ }
+
+gsm0808_cell_id_list_add(&cil, &cil) --> rc = 0
+ cell_id_list lac[3] = {
+ 0: 123
+ 1: 456
+ 2: 789
+ }
+
+gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = -22
+ cell_id_list lac[3] = {
+ 0: 123
+ 1: 456
+ 2: 789
+ }
+
+can't add to BSS list
+ cell_id_list bss[0]
+
+gsm0808_cell_id_list_add(&cil, &lac1) --> rc = -22
+ cell_id_list bss[0]
+
+other types (including NO_CELL) take on new type iff empty
+ cell_id_list no_cell[0]
+
+gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = 1
+ cell_id_list cgi[1] = {
+ 0: 001-02-3-4
+ }
+
+gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = 0
+ cell_id_list cgi[1] = {
+ 0: 001-02-3-4
+ }
+
+gsm0808_cell_id_list_add(&cil, &cgi2) --> rc = 2
+ cell_id_list cgi[3] = {
+ 0: 001-02-3-4
+ 1: 001-002-3-4
+ 2: 005-006-7-8
+ }
+
+gsm0808_cell_id_list_add(&cil, &cgi2) --> rc = 0
+ cell_id_list cgi[3] = {
+ 0: 001-02-3-4
+ 1: 001-002-3-4
+ 2: 005-006-7-8
+ }
+
+cil.id_list_len = 126
+gsm0808_cell_id_list_add(&cil, &cgi2a) --> rc = 1
+cil.id_list_len = 127
+
+cil.id_list_len = 126
+gsm0808_cell_id_list_add(&cil, &cgi3) --> rc = -28
+cil.id_list_len = 127
+gsm0808_cell_id_list_add(&cil, &cgi2a) --> rc = -28
+cil.id_list_len = 127
+------- test_cell_id_list_add done
Done