summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gsm/gsm0808_utils.h11
-rw-r--r--include/osmocom/gsm/protocol/gsm_08_08.h3
-rw-r--r--src/gsm/gsm0808_utils.c143
-rw-r--r--src/gsm/libosmogsm.map6
-rw-r--r--tests/gsm0808/gsm0808_test.c61
-rw-r--r--tests/gsm0808/gsm0808_test.ok90
6 files changed, 216 insertions, 98 deletions
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index 8e71b43c..8cdb74bb 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -55,6 +55,17 @@ struct gsm0808_cell_id_list2 {
unsigned int id_list_len;
};
+extern const struct value_string gsm0808_cell_id_discr_names[];
+static inline const char *gsm0808_cell_id_discr_name(enum CELL_IDENT id_discr)
+{ return get_value_string(gsm0808_cell_id_discr_names, id_discr); }
+
+const char *gsm0808_cell_id_name(const struct gsm0808_cell_id *cid);
+const char *gsm0808_cell_id_name2(const struct gsm0808_cell_id *cid);
+const char *gsm0808_cell_id_list_name(const struct gsm0808_cell_id_list2 *cil);
+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);
+
uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
const struct sockaddr_storage *ss);
int gsm0808_dec_aoip_trasp_addr(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 4539b960..5d2864ff 100644
--- a/include/osmocom/gsm/protocol/gsm_08_08.h
+++ b/include/osmocom/gsm/protocol/gsm_08_08.h
@@ -10,7 +10,8 @@
/*
* this is from GSM 03.03 CGI but is copied in GSM 08.08
- * in § 3.2.2.27 for Cell Identifier List
+ * in § 3.2.2.27 for Cell Identifier List.
+ * See gsm0808_cell_id_discr_name() for a human readable representation.
*/
enum CELL_IDENT {
CELL_IDENT_WHOLE_GLOBAL = 0,
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 73d9362e..8ef8e240 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -1130,4 +1130,147 @@ int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
return 0;
}
+/*! Print a human readable name of the cell identifier to the char buffer.
+ * This is useful both for struct gsm0808_cell_id and struct gsm0808_cell_id_list2.
+ * See also gsm0808_cell_id_name() and gsm0808_cell_id_list_name().
+ * \param[out] buf Destination buffer to write string representation to.
+ * \param[in] buflen Amount of memory available in \a buf.
+ * \param[in] id_discr Cell Identifier type.
+ * \param[in] u Cell Identifer value.
+ * \returns Like snprintf(): the amount of characters (excluding terminating nul) written,
+ * or that would have been written if the buffer were large enough.
+ */
+int gsm0808_cell_id_u_name(char *buf, size_t buflen,
+ enum CELL_IDENT id_discr, const union gsm0808_cell_id_u *u)
+{
+ switch (id_discr) {
+ case CELL_IDENT_LAC:
+ return snprintf(buf, buflen, "%u", u->lac);
+ case CELL_IDENT_CI:
+ return snprintf(buf, buflen, "%u", u->ci);
+ case CELL_IDENT_LAC_AND_CI:
+ return snprintf(buf, buflen, "%u-%u", u->lac_and_ci.lac, u->lac_and_ci.ci);
+ case CELL_IDENT_LAI_AND_LAC:
+ return snprintf(buf, buflen, "%s", osmo_lai_name(&u->lai_and_lac));
+ case CELL_IDENT_WHOLE_GLOBAL:
+ return snprintf(buf, buflen, "%s", osmo_cgi_name(&u->global));
+ default:
+ /* For CELL_IDENT_BSS and CELL_IDENT_NO_CELL, just print the discriminator.
+ * Same for kinds we have no string representation of yet. */
+ return snprintf(buf, buflen, "%s", gsm0808_cell_id_discr_name(id_discr));
+ }
+}
+
+/*! value_string[] for enum CELL_IDENT. */
+const struct value_string gsm0808_cell_id_discr_names[] = {
+ { CELL_IDENT_WHOLE_GLOBAL, "CGI" },
+ { CELL_IDENT_LAC_AND_CI, "LAC-CI" },
+ { CELL_IDENT_CI, "CI" },
+ { CELL_IDENT_NO_CELL, "NO-CELL" },
+ { CELL_IDENT_LAI_AND_LAC, "LAI" },
+ { CELL_IDENT_LAC, "LAC" },
+ { CELL_IDENT_BSS, "BSS" },
+ { CELL_IDENT_UTRAN_PLMN_LAC_RNC, "UTRAN-PLMN-LAC-RNC" },
+ { CELL_IDENT_UTRAN_RNC, "UTRAN-RNC" },
+ { CELL_IDENT_UTRAN_LAC_RNC, "UTRAN-LAC-RNC" },
+ { 0, NULL }
+};
+
+#define APPEND_THING(func, args...) do { \
+ int remain = buflen - (pos - buf); \
+ int l = func(pos, remain, ##args); \
+ if (l < 0 || l > remain) \
+ pos = buf + buflen; \
+ else \
+ pos += l; \
+ if (l > 0) \
+ total_len += l; \
+ } while(0)
+#define APPEND_STR(fmt, args...) APPEND_THING(snprintf, fmt, ##args)
+#define APPEND_CELL_ID_U(DISCR, U) APPEND_THING(gsm0808_cell_id_u_name, DISCR, U)
+
+static const char *gsm0808_cell_id_name_buf(const struct gsm0808_cell_id *cid,
+ char *buf, size_t buflen)
+{
+ char *pos = buf;
+ int total_len = 0;
+ APPEND_STR("%s:", gsm0808_cell_id_discr_name(cid->id_discr));
+ APPEND_CELL_ID_U(cid->id_discr, &cid->id);
+ return buf;
+}
+
+/*! Return a human readable representation of a Cell Identifier, like "LAC:123"
+ * or "CGI:001-01-42-23".
+ * \param[in] cid Cell Identifer.
+ * \returns String in a static buffer.
+ */
+const char *gsm0808_cell_id_name(const struct gsm0808_cell_id *cid)
+{
+ static char buf[64];
+ return gsm0808_cell_id_name_buf(cid, buf, sizeof(buf));
+}
+
+/*! Like gsm0808_cell_id_name() but uses a different static buffer.
+ * \param[in] cid Cell Identifer.
+ * \returns String in a static buffer.
+ */
+const char *gsm0808_cell_id_name2(const struct gsm0808_cell_id *cid)
+{
+ static char buf[64];
+ return gsm0808_cell_id_name_buf(cid, buf, sizeof(buf));
+}
+
+/*! Return a human readable representation of the Cell Identifier List, like
+ * "LAC[2]:{123, 456}".
+ * The return value semantics are like snprintf() and thus allow ensuring a complete
+ * untruncated string by determining the required string length from the return value.
+ * If buflen > 0, always nul-terminate the string in buf, also when it is truncated.
+ * If buflen == 0, do not modify buf, just return the would-be length.
+ * \param[out] buf Destination buffer to write string representation to.
+ * \param[in] buflen Amount of memory available in \a buf.
+ * \param[in] cil Cell Identifer List.
+ * \returns Like snprintf(): the amount of characters (excluding terminating nul) written,
+ * or that would have been written if the buffer were large enough.
+ */
+int gsm0808_cell_id_list_name_buf(char *buf, size_t buflen, const struct gsm0808_cell_id_list2 *cil)
+{
+ char *pos = buf;
+ int total_len = 0;
+ int i;
+
+ APPEND_STR("%s[%u]", gsm0808_cell_id_discr_name(cil->id_discr), cil->id_list_len);
+
+ switch (cil->id_discr) {
+ case CELL_IDENT_BSS:
+ case CELL_IDENT_NO_CELL:
+ return total_len;
+ default:
+ break;
+ }
+
+ APPEND_STR(":{");
+
+ for (i = 0; i < cil->id_list_len; i++) {
+ if (i)
+ APPEND_STR(", ");
+ APPEND_CELL_ID_U(cil->id_discr, &cil->id_list[i]);
+ }
+
+ APPEND_STR("}");
+ return total_len;
+}
+
+/*! Return a human-readable representation of \a cil in a static buffer.
+ * If the list is too long, the output may be truncated.
+ * See also gsm0808_cell_id_list_name_buf(). */
+const char *gsm0808_cell_id_list_name(const struct gsm0808_cell_id_list2 *cil)
+{
+ static char buf[1024];
+ gsm0808_cell_id_list_name_buf(buf, sizeof(buf), cil);
+ return buf;
+}
+
+#undef APPEND_STR
+#undef APPEND_CELL_ID_U
+
/*! @} */
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 388fcc04..f04fd58c 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -179,6 +179,12 @@ gsm0808_dec_cell_id_list2;
gsm0808_cell_id_list_add;
gsm0808_enc_cell_id;
gsm0808_dec_cell_id;
+gsm0808_cell_id_name;
+gsm0808_cell_id_name2;
+gsm0808_cell_id_list_name;
+gsm0808_cell_id_list_name_buf;
+gsm0808_cell_id_discr_names;
+gsm0808_cell_id_u_name;
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 49673fe4..78238ff3 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -1073,36 +1073,12 @@ static void test_gsm0808_enc_dec_cell_id_list_multi_global()
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");
- }
+ printf(" cell_id_list == %s\n", gsm0808_cell_id_list_name(cil));
}
void test_cell_id_list_add() {
+ size_t zu;
+
const struct gsm0808_cell_id_list2 cgi1 = {
.id_discr = CELL_IDENT_WHOLE_GLOBAL,
.id_list_len = 1,
@@ -1220,7 +1196,7 @@ void test_cell_id_list_add() {
#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); \
+ printf("gsm0808_cell_id_list_add(&cil, &" #other_cil ") --> rc = %d\n", rc); \
OSMO_ASSERT(rc == expect_rc); \
} while(0)
@@ -1233,13 +1209,13 @@ void test_cell_id_list_add() {
ADD(cil, 0);
ADD(cgi1, -EINVAL);
- printf("\ncan't add to BSS list\n");
+ printf("* can'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");
+ printf("* other 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);
@@ -1248,15 +1224,34 @@ void test_cell_id_list_add() {
ADD(cgi2, 2);
ADD(cgi2, 0);
+ printf("* test gsm0808_cell_id_list_name_buf()'s return val\n");
+ zu = strlen(gsm0808_cell_id_list_name(&cil));
+ printf(" strlen(gsm0808_cell_id_list_name(cil)) == %zu\n", zu);
+ zu ++;
+ while (1) {
+ char buf[128] = "?";
+ int rc;
+ OSMO_ASSERT(zu < sizeof(buf));
+ buf[zu] = '#';
+ rc = gsm0808_cell_id_list_name_buf(buf, zu, &cil);
+ printf(" gsm0808_cell_id_list_name_buf(buf, %zu, cil)) == %d \"%s\"\n",
+ zu, rc, buf);
+ OSMO_ASSERT(buf[zu] == '#');
+ if (!zu)
+ break;
+ zu /= 2;
+ }
+
+ printf("* list-full behavior\n");
cil.id_list_len = GSM0808_CELL_ID_LIST2_MAXLEN - 1;
- printf("\ncil.id_list_len = %u", cil.id_list_len);
+ printf("cil.id_list_len = %u\n", 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);
+ printf("cil.id_list_len = %u\n", cil.id_list_len);
ADD_QUIET(cgi3, -ENOSPC);
- printf("cil.id_list_len = %u", cil.id_list_len);
+ printf("cil.id_list_len = %u\n", cil.id_list_len);
ADD_QUIET(cgi2a, -ENOSPC);
printf("cil.id_list_len = %u\n", cil.id_list_len);
diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok
index 34d7ebfd..6cd7982b 100644
--- a/tests/gsm0808/gsm0808_test.ok
+++ b/tests/gsm0808/gsm0808_test.ok
@@ -21,84 +21,46 @@ Testing creating DTAP
Testing prepend DTAP
test_gsm0808_enc_dec_cell_id_list_lac: encoded: 1a 07 05 01 24 ab cd 56 78 (rc = 9)
------- test_cell_id_list_add
- cell_id_list cgi[0] = {
- }
-
+ cell_id_list == CGI[0]:{}
gsm0808_cell_id_list_add(&cil, &lac1) --> rc = 1
- cell_id_list lac[1] = {
- 0: 123
- }
-
+ cell_id_list == LAC[1]:{123}
gsm0808_cell_id_list_add(&cil, &lac1) --> rc = 0
- cell_id_list lac[1] = {
- 0: 123
- }
-
+ cell_id_list == LAC[1]:{123}
gsm0808_cell_id_list_add(&cil, &lac2) --> rc = 2
- cell_id_list lac[3] = {
- 0: 123
- 1: 456
- 2: 789
- }
-
+ cell_id_list == LAC[3]:{123, 456, 789}
gsm0808_cell_id_list_add(&cil, &lac2) --> rc = 0
- cell_id_list lac[3] = {
- 0: 123
- 1: 456
- 2: 789
- }
-
+ cell_id_list == LAC[3]:{123, 456, 789}
gsm0808_cell_id_list_add(&cil, &cil) --> rc = 0
- cell_id_list lac[3] = {
- 0: 123
- 1: 456
- 2: 789
- }
-
+ cell_id_list == LAC[3]:{123, 456, 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]
-
+ cell_id_list == LAC[3]:{123, 456, 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]
-
+ 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
- }
-
+ cell_id_list == CGI[1]:{001-02-3-4}
gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = 0
- cell_id_list cgi[1] = {
- 0: 001-02-3-4
- }
-
+ cell_id_list == CGI[1]:{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
- }
-
+ cell_id_list == CGI[3]:{001-02-3-4, 001-002-3-4, 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
- }
-
+ cell_id_list == CGI[3]:{001-02-3-4, 001-002-3-4, 005-006-7-8}
+* test gsm0808_cell_id_list_name_buf()'s return val
+ strlen(gsm0808_cell_id_list_name(cil)) == 45
+ gsm0808_cell_id_list_name_buf(buf, 46, cil)) == 45 "CGI[3]:{001-02-3-4, 001-002-3-4, 005-006-7-8}"
+ gsm0808_cell_id_list_name_buf(buf, 23, cil)) == 45 "CGI[3]:{001-02-3-4, 00"
+ gsm0808_cell_id_list_name_buf(buf, 11, cil)) == 45 "CGI[3]:{00"
+ gsm0808_cell_id_list_name_buf(buf, 5, cil)) == 45 "CGI["
+ gsm0808_cell_id_list_name_buf(buf, 2, cil)) == 45 "C"
+ gsm0808_cell_id_list_name_buf(buf, 1, cil)) == 45 ""
+ gsm0808_cell_id_list_name_buf(buf, 0, cil)) == 45 "#"
+* list-full behavior
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