mirror of https://gerrit.osmocom.org/libosmocore
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
This commit is contained in:
parent
51660a6ade
commit
8114294bf2
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -270,6 +270,8 @@ ipa_send;
|
|||
|
||||
osmo_apn_qualify;
|
||||
osmo_apn_qualify_from_imsi;
|
||||
osmo_apn_to_str;
|
||||
osmo_apn_from_str;
|
||||
|
||||
local: *;
|
||||
};
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Done.
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue