These functions are currently part of openbsc but also needed by
other projects.

The function have been renamed as follows:

  gprs_apn_to_str -> osmo_apn_to_str
  gprs_str_to_apn -> osmo_apn_from_str

Sponsored-by: On-Waves ehf
---
 include/osmocom/gsm/apn.h |   4 ++
 src/gsm/apn.c             |  76 +++++++++++++++++++++++++++++
 src/gsm/libosmogsm.map    |   2 +
 tests/Makefile.am         |  10 ++--
 tests/gprs/gprs_test.c    | 122 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/gprs/gprs_test.ok   |   1 +
 tests/testsuite.at        |   6 +++
 7 files changed, 218 insertions(+), 3 deletions(-)
 create mode 100644 tests/gprs/gprs_test.c
 create mode 100644 tests/gprs/gprs_test.ok

diff --git a/include/osmocom/gsm/apn.h b/include/osmocom/gsm/apn.h
index d8d7399..9e3dca3 100644
--- a/include/osmocom/gsm/apn.h
+++ b/include/osmocom/gsm/apn.h
@@ -11,3 +11,7 @@
 char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni);
 char *osmo_apn_qualify_from_imsi(const char *imsi,
                                 const char *ni, int have_3dig_mnc);
+
+int osmo_apn_from_str(uint8_t *apn_enc, size_t max_apn_enc_len, const char 
*str);
+char * osmo_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t 
apn_enc_len);
+
diff --git a/src/gsm/apn.c b/src/gsm/apn.c
index 413130a..ef7190d 100644
--- a/src/gsm/apn.c
+++ b/src/gsm/apn.c
@@ -36,3 +36,79 @@ char *osmo_apn_qualify_from_imsi(const char *imsi,
        }
        return osmo_apn_qualify(atoi(cbuf), atoi(nbuf), ni);
 }
+
+/**
+ * Convert an encoded APN into a dot-separated string.
+ *
+ * \param out_str      the destination buffer (size must be >= 
max(app_enc_len,1))
+ * \param apn_enc      the encoded APN
+ * \param apn_enc_len  the length of the encoded APN
+ *
+ * \returns out_str on success and NULL otherwise
+ */
+char * osmo_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t 
apn_enc_len)
+{
+       char *str = out_str;
+       size_t rest_chars = apn_enc_len;
+
+       while (rest_chars > 0 && apn_enc[0]) {
+               size_t label_size = apn_enc[0];
+               if (label_size + 1 > rest_chars)
+                       return NULL;
+
+               memmove(str, apn_enc + 1, label_size);
+               str += label_size;
+               rest_chars -= label_size + 1;
+               apn_enc += label_size + 1;
+
+               if (rest_chars)
+                       *(str++) = '.';
+       }
+       str[0] = '\0';
+
+       return out_str;
+}
+
+/**
+ * Convert a dot-separated string into an encoded APN.
+ *
+ * \param apn_enc          the encoded APN
+ * \param max_apn_enc_len  the size of the apn_enc buffer
+ * \param str              the source string
+ *
+ * \returns out_str on success and NULL otherwise
+ */
+int osmo_apn_from_str(uint8_t *apn_enc, size_t max_apn_enc_len, const char 
*str)
+{
+       uint8_t *last_len_field;
+       int len;
+
+       /* Can we even write the length field to the output? */
+       if (max_apn_enc_len == 0)
+               return -1;
+
+       /* Remember where we need to put the length once we know it */
+       last_len_field = apn_enc;
+       len = 1;
+       apn_enc += 1;
+
+       while (str[0]) {
+               if (len >= max_apn_enc_len)
+                       return -1;
+
+               if (str[0] == '.') {
+                       *last_len_field = (apn_enc - last_len_field) - 1;
+                       last_len_field = apn_enc;
+               } else {
+                       *apn_enc = str[0];
+               }
+               apn_enc += 1;
+               str += 1;
+               len += 1;
+       }
+
+       *last_len_field = (apn_enc - last_len_field) - 1;
+
+       return len;
+}
+
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 0c0d9f7..2aef050 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -269,6 +269,8 @@ ipa_send;

 osmo_apn_qualify;
 osmo_apn_qualify_from_imsi;
+osmo_apn_to_str;
+osmo_apn_from_str;

 local: *;
 };
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 223535f..4442355 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,7 +6,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test   
        \
                  conv/conv_test auth/milenage_test lapd/lapd_test      \
                  gsm0808/gsm0808_test gsm0408/gsm0408_test             \
                 gb/bssgp_fc_test gb/gprs_bssgp_test gb/gprs_ns_test    \
-                kasumi/kasumi_test logging/logging_test fr/fr_test     \
+                gprs/gprs_test kasumi/kasumi_test                      \
+                logging/logging_test fr/fr_test                        \
                 loggingrb/loggingrb_test strrb/strrb_test              \
                 vty/vty_test comp128/comp128_test utils/utils_test     \
                 smscb/gsm0341_test stats/stats_test
@@ -45,6 +46,9 @@ gsm0808_gsm0808_test_LDADD = 
$(top_builddir)/src/libosmocore.la $(top_builddir)/
 gsm0408_gsm0408_test_SOURCES = gsm0408/gsm0408_test.c
 gsm0408_gsm0408_test_LDADD = $(top_builddir)/src/libosmocore.la 
$(top_builddir)/src/gsm/libosmogsm.la

+gprs_gprs_test_SOURCES = gprs/gprs_test.c
+gprs_gprs_test_LDADD = $(top_builddir)/src/libosmocore.la 
$(top_builddir)/src/gsm/libosmogsm.la
+
 lapd_lapd_test_SOURCES = lapd/lapd_test.c
 lapd_lapd_test_LDADD = $(top_builddir)/src/libosmocore.la 
$(top_builddir)/src/gsm/libosmogsm.la

@@ -116,8 +120,8 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) 
        \
              lapd/lapd_test.ok gsm0408/gsm0408_test.ok                 \
              gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err             \
              gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh                 \
-             gb/gprs_bssgp_test.ok                                     \
-             gb/gprs_ns_test.ok kasumi/kasumi_test.ok                  \
+             gb/gprs_bssgp_test.ok gb/gprs_ns_test.ok                  \
+             gprs/gprs_test.ok kasumi/kasumi_test.ok                   \
              msgfile/msgfile_test.ok msgfile/msgconfig.cfg             \
              logging/logging_test.ok logging/logging_test.err          \
              fr/fr_test.ok loggingrb/logging_test.ok                   \
diff --git a/tests/gprs/gprs_test.c b/tests/gprs/gprs_test.c
new file mode 100644
index 0000000..be80e5c
--- /dev/null
+++ b/tests/gprs/gprs_test.c
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/gsm/apn.h>
+
+static void apn_round_trip(const uint8_t *input, size_t len, const char 
*wanted_output)
+{
+       char output[len ? len : 1];
+       uint8_t encoded[len + 50];
+       char *out_str;
+       int enc_len;
+
+       /* decode and verify we have what we want */
+       out_str = osmo_apn_to_str(output, input, len);
+       OSMO_ASSERT(out_str);
+       OSMO_ASSERT(out_str == &output[0]);
+       OSMO_ASSERT(strlen(out_str) == strlen(wanted_output));
+       OSMO_ASSERT(strcmp(out_str, wanted_output) == 0);
+
+       /* encode and verify it */
+       if (len != 0) {
+               enc_len = osmo_apn_from_str(encoded, ARRAY_SIZE(encoded), 
wanted_output);
+               OSMO_ASSERT(enc_len == len);
+               OSMO_ASSERT(memcmp(encoded, input, enc_len) == 0);
+       } else {
+               enc_len = osmo_apn_from_str(encoded, 0, wanted_output);
+               OSMO_ASSERT(enc_len == -1);
+       }
+}
+
+static void test_gsm_03_03_apn(void)
+{
+
+       {
+               /* test invalid writes */
+               const uint8_t ref[10] = { 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xAB, 
0xAC, 0xAD, 0xAE, 0xAF };
+               uint8_t output[10];
+               int enc_len;
+
+               memcpy(output, ref, ARRAY_SIZE(output));
+               enc_len = osmo_apn_from_str(output, 0, "");
+               OSMO_ASSERT(enc_len == -1);
+               OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0);
+
+               memcpy(output, ref, ARRAY_SIZE(output));
+               enc_len = osmo_apn_from_str(output, 0, "foo");
+               OSMO_ASSERT(enc_len == -1);
+               OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0);
+
+               memcpy(output, ref, ARRAY_SIZE(output));
+               enc_len = osmo_apn_from_str(output, 1, "foo");
+               OSMO_ASSERT(enc_len == -1);
+               OSMO_ASSERT(memcmp(ref + 1, output + 1, ARRAY_SIZE(ref) - 1) == 
0);
+
+               memcpy(output, ref, ARRAY_SIZE(output));
+               enc_len = osmo_apn_from_str(output, 2, "foo");
+               OSMO_ASSERT(enc_len == -1);
+               OSMO_ASSERT(memcmp(ref + 2, output + 2, ARRAY_SIZE(ref) - 2) == 
0);
+
+               memcpy(output, ref, ARRAY_SIZE(output));
+               enc_len = osmo_apn_from_str(output, 3, "foo");
+               OSMO_ASSERT(enc_len == -1);
+               OSMO_ASSERT(memcmp(ref + 3, output + 3, ARRAY_SIZE(ref) - 3) == 
0);
+       }
+
+       {
+               /* single empty label */
+               uint8_t input[] = { 0x0 };
+               const char *output = "";
+               apn_round_trip(input, ARRAY_SIZE(input), output);
+       }
+
+       {
+               /* no label */
+               uint8_t input[] = { };
+               const char *output = "";
+               apn_round_trip(input, ARRAY_SIZE(input), output);
+       }
+
+       {
+               /* single label with A */
+               uint8_t input[] = { 0x1, 65 };
+               const char *output = "A";
+               apn_round_trip(input, ARRAY_SIZE(input), output);
+               OSMO_ASSERT(osmo_apn_to_str(NULL, input, ARRAY_SIZE(input) - 1) 
== NULL);
+       }
+
+       {
+               uint8_t input[] = { 0x3, 65, 66, 67, 0x2, 90, 122 };
+               const char *output = "ABC.Zz";
+               char tmp[strlen(output) + 1];
+               apn_round_trip(input, ARRAY_SIZE(input), output);
+               OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 1) 
== NULL);
+               OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 2) 
== NULL);
+               OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 4) 
== NULL);
+               OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 5) 
== NULL);
+               OSMO_ASSERT(osmo_apn_to_str(tmp, input, ARRAY_SIZE(input) - 6) 
== NULL);
+       }
+}
+
+const struct log_info_cat default_categories[] = {
+};
+
+static struct log_info info = {
+       .cat = default_categories,
+       .num_cat = ARRAY_SIZE(default_categories),
+};
+
+int main(int argc, char **argv)
+{
+       osmo_init_logging(&info);
+
+       test_gsm_03_03_apn();
+
+       printf("Done.\n");
+       return EXIT_SUCCESS;
+}
diff --git a/tests/gprs/gprs_test.ok b/tests/gprs/gprs_test.ok
new file mode 100644
index 0000000..619c561
--- /dev/null
+++ b/tests/gprs/gprs_test.ok
@@ -0,0 +1 @@
+Done.
diff --git a/tests/testsuite.at b/tests/testsuite.at
index a542798..85c3e8b 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -84,6 +84,12 @@ cat $abs_srcdir/gsm0408/gsm0408_test.ok > expout
 AT_CHECK([$abs_top_builddir/tests/gsm0408/gsm0408_test], [0], [expout], 
[ignore])
 AT_CLEANUP

+AT_SETUP([gprs])
+AT_KEYWORDS([gprs])
+cat $abs_srcdir/gprs/gprs_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [0], [expout], [ignore])
+AT_CLEANUP
+
 AT_SETUP([logging])
 AT_KEYWORDS([logging])
 cat $abs_srcdir/logging/logging_test.ok > expout
-- 
1.9.1

Reply via email to