diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2015-11-17 08:42:05 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2016-01-15 14:46:19 +0100 |
commit | 8114294bf29ac6e44822c0ae43d4b0819f11b022 (patch) | |
tree | 5d065eccbb2b24bc7cdf674676e2d44ff2cc43c9 | |
parent | 51660a6adefd59081f7f2883d76a875e8b2e89c9 (diff) |
gsm: Add APN conversion functions
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
-rw-r--r-- | include/osmocom/gsm/apn.h | 3 | ||||
-rw-r--r-- | src/gsm/apn.c | 75 | ||||
-rw-r--r-- | src/gsm/libosmogsm.map | 2 | ||||
-rw-r--r-- | tests/Makefile.am | 10 | ||||
-rw-r--r-- | tests/gprs/gprs_test.c | 122 | ||||
-rw-r--r-- | tests/gprs/gprs_test.ok | 1 | ||||
-rw-r--r-- | tests/testsuite.at | 6 |
7 files changed, 216 insertions, 3 deletions
diff --git a/include/osmocom/gsm/apn.h b/include/osmocom/gsm/apn.h index a256d973..b4ece3a2 100644 --- a/include/osmocom/gsm/apn.h +++ b/include/osmocom/gsm/apn.h @@ -14,3 +14,6 @@ char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni); * static buffer. */ 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 413130aa..ccf36b99 100644 --- a/src/gsm/apn.c +++ b/src/gsm/apn.c @@ -36,3 +36,78 @@ 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 917a77d2..7eebe7f1 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -270,6 +270,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 3dc9bd91..9d14350f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,7 +7,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 @@ -46,6 +47,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 @@ -117,8 +121,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 00000000..be80e5c0 --- /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 00000000..619c5618 --- /dev/null +++ b/tests/gprs/gprs_test.ok @@ -0,0 +1 @@ +Done. diff --git a/tests/testsuite.at b/tests/testsuite.at index a5427986..85c3e8bd 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 |