aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am18
-rw-r--r--tests/auc/Makefile.am14
-rw-r--r--tests/auc/auc_test.c118
-rw-r--r--tests/auc/auc_test.err23
-rw-r--r--tests/auc/gen_ts_55_205_test_sets/func_template.c57
-rw-r--r--tests/auc/gen_ts_55_205_test_sets/main_template.c13
-rwxr-xr-xtests/auc/gen_ts_55_205_test_sets/pdftxt_2_c.py3
-rw-r--r--tests/db/Makefile.am22
-rw-r--r--tests/db/db_test.c231
-rw-r--r--tests/db/db_test.err363
-rw-r--r--tests/db_upgrade/Makefile.am14
-rw-r--r--tests/db_upgrade/create_subscribers.vty47
-rw-r--r--tests/db_upgrade/create_subscribers_step2.sql6
-rw-r--r--tests/db_upgrade/db_upgrade_test.err (renamed from tests/gsup_server/gsup_server_test.err)0
-rw-r--r--tests/db_upgrade/db_upgrade_test.ok184
-rwxr-xr-xtests/db_upgrade/db_upgrade_test.sh83
-rw-r--r--tests/db_upgrade/hlr_db_v0.sql80
-rw-r--r--tests/db_upgrade/osmo-hlr.cfg6
-rw-r--r--tests/gsup/Makefile.am12
-rw-r--r--tests/gsup/gsup_test.c102
-rw-r--r--tests/gsup/gsup_test.err2
-rw-r--r--tests/gsup/gsup_test.ok31
-rw-r--r--tests/gsup_server/Makefile.am41
-rw-r--r--tests/gsup_server/gsup_server_test.c145
-rw-r--r--tests/gsup_server/gsup_server_test.ok94
-rw-r--r--tests/mslookup/Makefile.am72
-rw-r--r--tests/mslookup/mdns_test.c459
-rw-r--r--tests/mslookup/mdns_test.err254
-rw-r--r--tests/mslookup/mslookup_client_mdns_test.c255
-rw-r--r--tests/mslookup/mslookup_client_mdns_test.err14
-rw-r--r--tests/mslookup/mslookup_client_test.c245
-rw-r--r--tests/mslookup/mslookup_client_test.err47
-rw-r--r--tests/mslookup/mslookup_test.c88
-rw-r--r--tests/mslookup/mslookup_test.err22
-rw-r--r--tests/test_nodes.vty514
-rw-r--r--tests/test_subscriber.ctrl101
-rw-r--r--tests/test_subscriber.vty23
-rw-r--r--tests/test_subscriber_errors.ctrl48
-rw-r--r--tests/testsuite.at43
39 files changed, 3242 insertions, 652 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4da8ab1..41a9d47 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,8 +1,9 @@
SUBDIRS = \
auc \
- gsup_server \
db \
gsup \
+ db_upgrade \
+ mslookup \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
@@ -44,12 +45,14 @@ python-tests:
# don't run vty and ctrl tests concurrently so that the ports don't conflict
$(MAKE) vty-test
$(MAKE) ctrl-test
+ $(MAKE) db-upgrade-equivalence-test
else
python-tests:
echo "Not running python-based external tests (determined at configure-time)"
endif
VTY_TEST_DB = hlr_vty_test.db
+VTY_TEST ?= *.vty
# To update the VTY script from current application behavior,
# pass -u to vty_script_runner.py by doing:
@@ -61,12 +64,14 @@ vty-test:
osmo_verify_transcript_vty.py -v \
-n OsmoHLR -p 4258 \
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(VTY_TEST_DB)" \
- $(U) $(srcdir)/*.vty
- -rm -f $(VTY_TEST_DB)
- -rm $(VTY_TEST_DB)-*
+ $(U) $(srcdir)/$(VTY_TEST)
+ -rm -f $(VTY_TEST_DB) $(VTY_TEST_DB)-*
CTRL_TEST_DB = hlr_ctrl_test.db
+# Run a specific test with: 'make ctrl-test CTRL_TEST=test_subscriber.ctrl'
+CTRL_TEST ?= *.ctrl
+
# To update the CTRL script from current application behavior,
# pass -u to ctrl_script_runner.py by doing:
# make ctrl-test U=-u
@@ -77,10 +82,13 @@ ctrl-test:
osmo_verify_transcript_ctrl.py -v \
-p 4259 \
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(CTRL_TEST_DB)" \
- $(U) $(srcdir)/*.ctrl
+ $(U) $(srcdir)/$(CTRL_TEST)
-rm -f $(CTRL_TEST_DB)
-rm $(CTRL_TEST_DB)-*
+db-upgrade-equivalence-test:
+ $(MAKE) -C db_upgrade upgrade-equivalence-test
+
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
$(MAKE) $(AM_MAKEFLAGS) python-tests
diff --git a/tests/auc/Makefile.am b/tests/auc/Makefile.am
index a3814b6..9d0f726 100644
--- a/tests/auc/Makefile.am
+++ b/tests/auc/Makefile.am
@@ -2,7 +2,7 @@ SUBDIRS = gen_ts_55_205_test_sets
AM_CPPFLAGS = \
$(all_includes) \
- -I$(top_srcdir)/src \
+ -I$(top_srcdir)/include \
$(NULL)
AM_CFLAGS = \
@@ -23,17 +23,15 @@ EXTRA_DIST = \
auc_ts_55_205_test_sets.err \
$(NULL)
-check_PROGRAMS = auc_ts_55_205_test_sets
-
-noinst_PROGRAMS = auc_test
+check_PROGRAMS = auc_test auc_ts_55_205_test_sets
auc_test_SOURCES = \
auc_test.c \
$(NULL)
auc_test_LDADD = \
- $(top_srcdir)/src/auc.c \
- $(top_srcdir)/src/logging.c \
+ $(top_builddir)/src/auc.o \
+ $(top_builddir)/src/logging.o \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(NULL)
@@ -43,8 +41,8 @@ auc_ts_55_205_test_sets_SOURCES = \
$(NULL)
auc_ts_55_205_test_sets_LDADD = \
- $(top_srcdir)/src/auc.c \
- $(top_srcdir)/src/logging.c \
+ $(top_builddir)/src/auc.o \
+ $(top_builddir)/src/logging.o \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(NULL)
diff --git a/tests/auc/auc_test.c b/tests/auc/auc_test.c
index e23cc02..5906720 100644
--- a/tests/auc/auc_test.c
+++ b/tests/auc/auc_test.c
@@ -29,8 +29,8 @@
#include <osmocom/crypt/auth.h>
-#include "logging.h"
-#include "auc.h"
+#include <osmocom/hlr/logging.h>
+#include <osmocom/hlr/auc.h>
#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
#define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__);
@@ -113,16 +113,17 @@ int rand_get(uint8_t *rand, unsigned int len)
return len;
}
+/* Subscriber with 2G-only (COMP128v1) authentication data */
static void test_gen_vectors_2g_only(void)
{
- struct osmo_sub_auth_data aud2g;
- struct osmo_sub_auth_data aud3g;
+ struct osmo_sub_auth_data2 aud2g;
+ struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec;
int rc;
comment_start();
- aud2g = (struct osmo_sub_auth_data){
+ aud2g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1,
};
@@ -130,7 +131,7 @@ static void test_gen_vectors_2g_only(void)
osmo_hexparse("EB215756028D60E3275E613320AEC880",
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
- aud3g = (struct osmo_sub_auth_data){ 0 };
+ aud3g = (struct osmo_sub_auth_data2){ 0 };
next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
@@ -174,16 +175,18 @@ static void test_gen_vectors_2g_only(void)
comment_end();
}
+/* Subscriber with separate 2G (COMP128v1) and 3G (MILENAGE) authentication data,
+ * reflects the default configuration of sysmoUSIM-SJS1 */
static void test_gen_vectors_2g_plus_3g(void)
{
- struct osmo_sub_auth_data aud2g;
- struct osmo_sub_auth_data aud3g;
+ struct osmo_sub_auth_data2 aud2g;
+ struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec;
int rc;
comment_start();
- aud2g = (struct osmo_sub_auth_data){
+ aud2g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1,
};
@@ -191,9 +194,11 @@ static void test_gen_vectors_2g_plus_3g(void)
osmo_hexparse("EB215756028D60E3275E613320AEC880",
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
- aud3g = (struct osmo_sub_auth_data){
+ aud3g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE,
+ .u.umts.k_len = 16,
+ .u.umts.opc_len = 16,
.u.umts.sqn = 31,
};
@@ -284,10 +289,13 @@ void _test_gen_vectors_3g_only__expect_vecs(struct osmo_auth_vector vecs[3])
);
}
+/* Subscriber with only 3G (MILENAGE) authentication data,
+ * reflects the default configuration of sysmoISIM-SJA2. Resulting
+ * tuples are suitable for both 2G and 3G authentication */
static void test_gen_vectors_3g_only(void)
{
- struct osmo_sub_auth_data aud2g;
- struct osmo_sub_auth_data aud3g;
+ struct osmo_sub_auth_data2 aud2g;
+ struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec;
struct osmo_auth_vector vecs[3];
uint8_t auts[14];
@@ -296,11 +304,13 @@ static void test_gen_vectors_3g_only(void)
comment_start();
- aud2g = (struct osmo_sub_auth_data){ 0 };
+ aud2g = (struct osmo_sub_auth_data2){ 0 };
- aud3g = (struct osmo_sub_auth_data){
+ aud3g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE,
+ .u.umts.k_len = 16,
+ .u.umts.opc_len = 16,
.u.umts.sqn = 31,
};
@@ -454,7 +464,58 @@ static void test_gen_vectors_3g_only(void)
comment_end();
}
-void test_gen_vectors_bad_args()
+/* Subscriber with only 3G (XOR) authentication data,
+ * reflects the default configuration of sysmoTSIM-SJAx as well
+ * as many "Test USIM" cards. Resulting tuples are suitable for both
+ * 2G and 3G authentication */
+static void test_gen_vectors_3g_xor(void)
+{
+ struct osmo_sub_auth_data2 aud2g;
+ struct osmo_sub_auth_data2 aud3g;
+ struct osmo_auth_vector vec;
+ int rc;
+
+ comment_start();
+
+ aud2g = (struct osmo_sub_auth_data2){ 0 };
+
+ aud3g = (struct osmo_sub_auth_data2){
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = OSMO_AUTH_ALG_XOR_3G,
+ .u.umts.k_len = 16,
+ .u.umts.opc_len = 16,
+ .u.umts.sqn = 0,
+ };
+
+ osmo_hexparse("000102030405060708090a0b0c0d0e0f",
+ aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
+ osmo_hexparse("00000000000000000000000000000000",
+ aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
+ next_rand("b5039c57e4a75051551d1a390a71ce48", true);
+
+ vec = (struct osmo_auth_vector){ {0} };
+ VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
+ rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
+ VERBOSE_ASSERT(rc, == 1, "%d");
+ VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
+
+ VEC_IS(&vec,
+ " rand: b5039c57e4a75051551d1a390a71ce48\n"
+ " autn: 54e0a256565d0000b5029e54e0a25656\n"
+ " ck: 029e54e0a256565d141032067cc047b5\n"
+ " ik: 9e54e0a256565d141032067cc047b502\n"
+ " res: b5029e54e0a256565d141032067cc047\n"
+ " res_len: 10\n"
+ " kc: 98e880384887f9fe\n"
+ " sres: 0ec81877\n"
+ " auth_types: 03000000\n"
+ );
+
+ comment_end();
+}
+
+/* Test a variety of invalid authentication data combinations */
+void test_gen_vectors_bad_args(void)
{
struct osmo_auth_vector vec;
uint8_t auts[14];
@@ -462,39 +523,43 @@ void test_gen_vectors_bad_args()
int rc;
int i;
- struct osmo_sub_auth_data aud2g = {
+ struct osmo_sub_auth_data2 aud2g = {
.type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1,
};
- struct osmo_sub_auth_data aud3g = {
+ struct osmo_sub_auth_data2 aud3g = {
.type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE,
+ .u.umts.k_len = 16,
+ .u.umts.opc_len = 16,
};
- struct osmo_sub_auth_data aud2g_noalg = {
+ struct osmo_sub_auth_data2 aud2g_noalg = {
.type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_NONE,
};
- struct osmo_sub_auth_data aud3g_noalg = {
+ struct osmo_sub_auth_data2 aud3g_noalg = {
.type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_NONE,
+ .u.umts.k_len = 16,
+ .u.umts.opc_len = 16,
};
- struct osmo_sub_auth_data aud_notype = {
+ struct osmo_sub_auth_data2 aud_notype = {
.type = OSMO_AUTH_TYPE_NONE,
.algo = OSMO_AUTH_ALG_MILENAGE,
};
- struct osmo_sub_auth_data no_aud = {
+ struct osmo_sub_auth_data2 no_aud = {
.type = OSMO_AUTH_TYPE_NONE,
.algo = OSMO_AUTH_ALG_NONE,
};
struct {
- struct osmo_sub_auth_data *aud2g;
- struct osmo_sub_auth_data *aud3g;
+ struct osmo_sub_auth_data2 *aud2g;
+ struct osmo_sub_auth_data2 *aud3g;
uint8_t *rand_auts;
uint8_t *auts;
const char *label;
@@ -613,15 +678,20 @@ int main(int argc, char **argv)
void *tall_ctx = talloc_named_const(NULL, 1, "auc_test");
osmo_init_logging2(tall_ctx, &hlr_log_info);
- log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
+ log_set_print_filename2(osmo_stderr_target,
+ cmdline_opts.verbose ?
+ LOG_FILENAME_BASENAME :
+ LOG_FILENAME_NONE);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
test_gen_vectors_2g_only();
test_gen_vectors_2g_plus_3g();
test_gen_vectors_3g_only();
+ test_gen_vectors_3g_xor();
test_gen_vectors_bad_args();
printf("Done\n");
diff --git a/tests/auc/auc_test.err b/tests/auc/auc_test.err
index 0a4d9af..f83e814 100644
--- a/tests/auc/auc_test.err
+++ b/tests/auc/auc_test.err
@@ -217,6 +217,29 @@ DAUC vector [2]: auth_types = 0x3
===== test_gen_vectors_3g_only: SUCCESS
+===== test_gen_vectors_3g_xor
+aud3g.u.umts.sqn == 0
+DAUC Computing 1 auth vector: 3G only (2G derived from 3G keys)
+DAUC 3G: k = 000102030405060708090a0b0c0d0e0f
+DAUC 3G: opc = 00000000000000000000000000000000
+DAUC 3G: for sqn ind 0, previous sqn was 0
+DAUC vector [0]: rand = b5039c57e4a75051551d1a390a71ce48
+DAUC vector [0]: sqn = 0
+DAUC vector [0]: autn = 54e0a256565d0000b5029e54e0a25656
+DAUC vector [0]: ck = 029e54e0a256565d141032067cc047b5
+DAUC vector [0]: ik = 9e54e0a256565d141032067cc047b502
+DAUC vector [0]: res = b5029e54e0a256565d141032067cc047
+DAUC vector [0]: res_len = 16
+DAUC vector [0]: deriving 2G from 3G
+DAUC vector [0]: kc = 98e880384887f9fe
+DAUC vector [0]: sres = 0ec81877
+DAUC vector [0]: auth_types = 0x3
+rc == 1
+aud3g.u.umts.sqn == 0
+vector matches expectations
+===== test_gen_vectors_3g_xor: SUCCESS
+
+
===== test_gen_vectors_bad_args
- no auth data (a)
diff --git a/tests/auc/gen_ts_55_205_test_sets/func_template.c b/tests/auc/gen_ts_55_205_test_sets/func_template.c
index 0865432..f8b4097 100644
--- a/tests/auc/gen_ts_55_205_test_sets/func_template.c
+++ b/tests/auc/gen_ts_55_205_test_sets/func_template.c
@@ -24,43 +24,46 @@
static void {func_name}(void)
{{
- struct osmo_sub_auth_data aud2g;
- struct osmo_sub_auth_data aud3g;
- struct osmo_auth_vector vec;
- int rc;
+ struct osmo_sub_auth_data2 aud2g;
+ struct osmo_sub_auth_data2 aud3g;
+ struct osmo_auth_vector vec;
+ int rc;
- comment_start();
+ comment_start();
- aud2g = (struct osmo_sub_auth_data){{ 0 }};
+ aud2g = (struct osmo_sub_auth_data2){{ 0 }};
- aud3g = (struct osmo_sub_auth_data){{
- .type = OSMO_AUTH_TYPE_UMTS,
- .algo = OSMO_AUTH_ALG_MILENAGE,
+ aud3g = (struct osmo_sub_auth_data2){{
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = OSMO_AUTH_ALG_MILENAGE,
+ .u.umts.k_len = 16,
+ .u.umts.opc_len = 16,
.u.umts.sqn = 31,
- }};
+ }};
- osmo_hexparse("{Ki}",
- aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
- osmo_hexparse("{OPc}",
- aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
+ osmo_hexparse("{Ki}",
+ aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
+ osmo_hexparse("{OPc}",
+ aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
- osmo_hexparse("{RAND}",
- fake_rand, sizeof(fake_rand));
+ osmo_hexparse("{RAND}",
+ fake_rand, sizeof(fake_rand));
- vec = (struct osmo_auth_vector){{ {{0}} }};
+ vec = (struct osmo_auth_vector){{ {{0}} }};
+ vec.res_len = 8;
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
- rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
- VERBOSE_ASSERT(rc, == 1, "%d");
+ rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
+ VERBOSE_ASSERT(rc, == 1, "%d");
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
- VEC_IS(&vec,
- " rand: {RAND}\n"
- " ck: {MIL3G-CK}\n"
- " ik: {MIL3G-IK}\n"
- " res: {MIL3G-RES}0000000000000000\n"
- " kc: {Kc}\n"
- " sres: {SRES#1}\n"
- );
+ VEC_IS(&vec,
+ " rand: {RAND}\n"
+ " ck: {MIL3G-CK}\n"
+ " ik: {MIL3G-IK}\n"
+ " res: {MIL3G-RES}0000000000000000\n"
+ " kc: {Kc}\n"
+ " sres: {SRES#1}\n"
+ );
comment_end();
}}
diff --git a/tests/auc/gen_ts_55_205_test_sets/main_template.c b/tests/auc/gen_ts_55_205_test_sets/main_template.c
index a78bddb..d810ba9 100644
--- a/tests/auc/gen_ts_55_205_test_sets/main_template.c
+++ b/tests/auc/gen_ts_55_205_test_sets/main_template.c
@@ -33,8 +33,8 @@
#include <osmocom/crypt/auth.h>
-#include "logging.h"
-#include "auc.h"
+#include <osmocom/hlr/logging.h>
+#include <osmocom/hlr/auc.h>
#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
#define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__);
@@ -55,7 +55,7 @@ char *vec_str(const struct osmo_auth_vector *vec)
if (pos >= end) \
return buf; \
pos += snprintf(pos, sizeof(buf) - (pos - buf), \
- " " #what ": %s\n", \
+ " " #what ": %s\n", \
osmo_hexdump_nospc((void*)&vec->what, sizeof(vec->what)))
append(rand);
@@ -71,7 +71,7 @@ char *vec_str(const struct osmo_auth_vector *vec)
#define VEC_IS(vec, expect) do { \
char *_is = vec_str(vec); \
- if (strcmp(_is, expect)) { \
+ if (strcmp(_is, expect)) { \
fprintf(stderr, "MISMATCH! expected ==\n%s\n", \
expect); \
char *a = _is; \
@@ -100,15 +100,16 @@ int rand_get(uint8_t *rand, unsigned int len)
FUNCTIONS
-int main()
+int main(int argc, char **argv)
{
printf("3GPP TS 55.205 Test Sets\n");
void *tall_ctx = talloc_named_const(NULL, 1, "test");
msgb_talloc_ctx_init(tall_ctx, 0);
osmo_init_logging2(tall_ctx, &hlr_log_info);
- log_set_print_filename(osmo_stderr_target, 0);
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
diff --git a/tests/auc/gen_ts_55_205_test_sets/pdftxt_2_c.py b/tests/auc/gen_ts_55_205_test_sets/pdftxt_2_c.py
index b01a797..9df65b5 100755
--- a/tests/auc/gen_ts_55_205_test_sets/pdftxt_2_c.py
+++ b/tests/auc/gen_ts_55_205_test_sets/pdftxt_2_c.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-# FIXME: use python3 once buildslaves are updated.
+#!/usr/bin/env python3
# Convert test sets pasted from 3GPP TS 55.205 to C code.
# (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
diff --git a/tests/db/Makefile.am b/tests/db/Makefile.am
index afda5be..b07460e 100644
--- a/tests/db/Makefile.am
+++ b/tests/db/Makefile.am
@@ -1,7 +1,10 @@
-AM_CFLAGS = \
+AM_CPPFLAGS = \
$(all_includes) \
- -I$(top_srcdir)/src \
- -I$(top_builddir)/src \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ $(NULL)
+
+AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
@@ -26,16 +29,21 @@ db_test_SOURCES = \
$(NULL)
db_test_LDADD = \
- $(top_srcdir)/src/db.c \
- $(top_srcdir)/src/db_hlr.c \
- $(top_srcdir)/src/db_auc.c \
- $(top_srcdir)/src/logging.c \
+ $(top_builddir)/src/logging.o \
+ $(top_builddir)/src/db_auc.o \
+ $(top_builddir)/src/db_hlr.o \
+ $(top_builddir)/src/db.o \
+ $(top_builddir)/src/cni_peer_id.o \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(SQLITE3_LIBS) \
$(NULL)
+if DB_SQLITE_DEBUG
+db_test_LDADD += $(top_builddir)/src/db_debug.o
+endif
+
.PHONY: db_test.db update_exp manual manual-nonverbose manual-gdb
db_test.db:
rm -f db_test.db
diff --git a/tests/db/db_test.c b/tests/db/db_test.c
index fdd62c5..bdf1393 100644
--- a/tests/db/db_test.c
+++ b/tests/db/db_test.c
@@ -27,8 +27,9 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
-#include "db.h"
-#include "logging.h"
+#include <osmocom/gsupclient/cni_peer_id.h>
+#include <osmocom/hlr/db.h>
+#include <osmocom/hlr/logging.h>
#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
#define comment(fmt, args...) fprintf(stderr, "\n--- " fmt "\n\n", ## args);
@@ -51,7 +52,12 @@ static void _fill_invalid(void *dest, size_t size)
* The return code is then available in g_rc. */
#define ASSERT_RC(call, expect_rc) \
do { \
- fprintf(stderr, #call " --> " #expect_rc "\n"); \
+ if ((expect_rc) == -ENOKEY) \
+ fprintf(stderr, #call " --> -ENOKEY\n"); \
+ else if ((expect_rc) == -ENOTSUP) \
+ fprintf(stderr, #call " --> -ENOTSUP\n"); \
+ else \
+ fprintf(stderr, #call " --> " #expect_rc "\n"); \
g_rc = call; \
if (g_rc != (expect_rc)) \
fprintf(stderr, " MISMATCH: got rc = %d, expected: " \
@@ -67,7 +73,12 @@ static void _fill_invalid(void *dest, size_t size)
do { \
int rc; \
fill_invalid(g_subscr); \
- fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> " \
+ if ((expect_rc) == -ENOKEY) \
+ fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> -ENOKEY \n"); \
+ else if ((expect_rc) == -ENOTSUP) \
+ fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> -ENOTSUP \n"); \
+ else \
+ fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> " \
#expect_rc "\n"); \
rc = db_subscr_get_by_##by(dbc, val, &g_subscr); \
if (rc != (expect_rc)) \
@@ -105,22 +116,22 @@ static void _fill_invalid(void *dest, size_t size)
#define ASSERT_DB_GET_AUC(imsi, expect_rc) \
do { \
struct osmo_auth_vector vec[N_VECTORS]; \
- ASSERT_RC(db_get_auc(dbc, imsi, 3, vec, N_VECTORS, NULL, NULL), expect_rc); \
+ ASSERT_RC(db_get_auc(dbc, imsi, 3, vec, N_VECTORS, NULL, NULL, false), expect_rc); \
} while (0)
/* Not linking the real auc_compute_vectors(), just returning num_vec.
* This gets called by db_get_auc(), but we're only interested in its rc. */
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
- struct osmo_sub_auth_data *aud2g,
- struct osmo_sub_auth_data *aud3g,
+ struct osmo_sub_auth_data2 *aud2g,
+ struct osmo_sub_auth_data2 *aud3g,
const uint8_t *rand_auts, const uint8_t *auts)
{ return num_vec; }
static struct db_context *dbc = NULL;
static void *ctx = NULL;
static struct hlr_subscriber g_subscr;
-static struct osmo_sub_auth_data g_aud2g;
-static struct osmo_sub_auth_data g_aud3g;
+static struct osmo_sub_auth_data2 g_aud2g;
+static struct osmo_sub_auth_data2 g_aud3g;
static int g_rc;
static int64_t g_id;
@@ -135,6 +146,8 @@ void dump_subscr(struct hlr_subscriber *subscr)
#define Ps(name) \
if (*subscr->name) \
Pfo(name, "'%s'", subscr)
+#define Pgt(name) \
+ Pfv(name, "%s", osmo_ipa_name_to_str(&subscr->name))
#define Pd(name) \
Pfv(name, "%"PRId64, (int64_t)subscr->name)
#define Pd_nonzero(name) \
@@ -167,18 +180,21 @@ void dump_subscr(struct hlr_subscriber *subscr)
#undef Pb
}
-void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
+void dump_aud(const char *label, struct osmo_sub_auth_data2 *aud)
{
if (aud->type == OSMO_AUTH_TYPE_NONE) {
fprintf(stderr, "%s: none\n", label);
return;
}
- fprintf(stderr, "%s: struct osmo_sub_auth_data {\n", label);
+ fprintf(stderr, "%s: struct osmo_sub_auth_data2 {\n", label);
#define Pf(name, fmt) \
Pfo(name, fmt, aud)
#define Phex(name) \
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
+#define Phexl(name, len) \
+ Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, aud->len))
+
Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
@@ -187,9 +203,9 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
Phex(u.gsm.ki);
break;
case OSMO_AUTH_TYPE_UMTS:
- Phex(u.umts.opc);
+ Phexl(u.umts.opc, u.umts.opc_len);
Pf(u.umts.opc_is_op, "%u");
- Phex(u.umts.k);
+ Phexl(u.umts.k, u.umts.k_len);
Phex(u.umts.amf);
if (aud->u.umts.sqn) {
Pf(u.umts.sqn, "%"PRIu64);
@@ -206,6 +222,18 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
#undef Pf
#undef Phex
+#undef Phexl
+}
+
+void db_raw_sql(struct db_context *dbc, const char *sql)
+{
+ sqlite3_stmt *stmt;
+
+ fprintf(stderr, "raw SQL: %s\n", sql);
+ ASSERT_RC(sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL), SQLITE_OK);
+ ASSERT_RC(sqlite3_step(stmt), SQLITE_DONE);
+ db_remove_reset(stmt);
+ sqlite3_finalize(stmt);
}
static const char *imsi0 = "123456789000000";
@@ -214,7 +242,15 @@ static const char *imsi2 = "123456789000002";
static const char *short_imsi = "123456";
static const char *unknown_imsi = "999999999";
-static void test_subscr_create_update_sel_delete()
+static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,
+ const char *vlr_or_sgsn_number, bool is_ps)
+{
+ struct osmo_ipa_name vlr_nr;
+ osmo_ipa_name_set_str(&vlr_nr, vlr_or_sgsn_number);
+ return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL);
+}
+
+static void test_subscr_create_update_sel_delete(void)
{
int64_t id0, id1, id2, id_short;
comment_start();
@@ -230,13 +266,13 @@ static void test_subscr_create_update_sel_delete()
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
ASSERT_SEL(imsi, imsi2, 0);
id2 = g_subscr.id;
- ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
+ ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
ASSERT_SEL(imsi, imsi0, 0);
- ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
- ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
+ ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
+ ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
ASSERT_SEL(imsi, imsi1, 0);
- ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
- ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
+ ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
+ ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
ASSERT_SEL(imsi, imsi2, 0);
ASSERT_RC(db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
@@ -365,39 +401,39 @@ static void test_subscr_create_update_sel_delete()
comment("Record LU for PS and CS (SGSN and VLR names)");
- ASSERT_RC(db_subscr_lu(dbc, id0, "5952", true), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "5952", true), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "712", false), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "712", false), 0);
ASSERT_SEL(id, id0, 0);
comment("Record LU for PS and CS (SGSN and VLR names) *again*");
- ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "111", true), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "111", true), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "222", false), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "222", false), 0);
ASSERT_SEL(id, id0, 0);
comment("Unset LU info for PS and CS (SGSN and VLR names)");
- ASSERT_RC(db_subscr_lu(dbc, id0, "", true), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "", true), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "", false), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "", false), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "111", true), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "222", false), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, NULL, true), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, NULL, true), 0);
ASSERT_SEL(id, id0, 0);
- ASSERT_RC(db_subscr_lu(dbc, id0, NULL, false), 0);
+ ASSERT_RC(db_subscr_lu_str(dbc, id0, NULL, false), 0);
ASSERT_SEL(id, id0, 0);
comment("Record LU for non-existent ID");
- ASSERT_RC(db_subscr_lu(dbc, 99999, "5952", true), -ENOENT);
- ASSERT_RC(db_subscr_lu(dbc, 99999, "712", false), -ENOENT);
+ ASSERT_RC(db_subscr_lu_str(dbc, 99999, "5952", true), -ENOENT);
+ ASSERT_RC(db_subscr_lu_str(dbc, 99999, "712", false), -ENOENT);
ASSERT_SEL(id, 99999, -ENOENT);
comment("Purge and un-purge PS and CS");
@@ -509,7 +545,7 @@ static const struct sub_auth_data_str *mk_aud_3g(enum osmo_auth_algo algo,
return &aud;
}
-static void test_subscr_aud()
+static void test_subscr_aud(void)
{
int64_t id;
@@ -554,7 +590,7 @@ static void test_subscr_aud()
ASSERT_SEL_AUD(imsi0, 0, id);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
- mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
+ mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
0);
ASSERT_SEL_AUD(imsi0, 0, id);
@@ -572,7 +608,7 @@ static void test_subscr_aud()
-ENOENT);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
- mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
+ mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
0);
ASSERT_SEL_AUD(imsi0, 0, id);
@@ -675,12 +711,12 @@ static void test_subscr_aud()
ASSERT_SEL_AUD(imsi0, 0, id);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
- mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")),
+ mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")),
-EINVAL);
ASSERT_SEL_AUD(imsi0, 0, id);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
- mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")),
+ mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")),
-EINVAL);
ASSERT_SEL_AUD(imsi0, 0, id);
@@ -749,7 +785,71 @@ static void test_subscr_aud()
comment_end();
}
-static void test_subscr_sqn()
+/* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the
+ * table structure. */
+static void test_subscr_aud_invalid_len(void)
+{
+ int64_t id;
+
+ comment_start();
+ comment("Create subscriber");
+ ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
+ ASSERT_SEL(imsi, imsi0, 0);
+ id = g_subscr.id;
+
+
+ /* Invalid Ki length */
+ comment("Set auth data, 2G only, with invalid Ki length");
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")),
+ 0);
+ /* Use raw SQL to avoid length check in db_subscr_update_aud_by_id(). This changes all rows in the table, which
+ * is fine for this test (implicit WHERE 1). */
+ db_raw_sql(dbc, "UPDATE auc_2g SET ki = '0123456789abcdef0123456789abcde'");
+ ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
+
+ comment("Remove 2G auth data");
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)),
+ 0);
+
+ /* Invalid K length */
+ comment("Set auth data, 3G only, with invalid K length");
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", true,
+ "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
+ 0);
+ db_raw_sql(dbc, "UPDATE auc_3g SET k = 'C01ffedC1cadaeAc1d1f1edAcac1aB0'");
+ ASSERT_SEL_AUD(imsi0, -EIO, id);
+
+ /* Invalid OP length */
+ comment("Set auth data, 3G only, with invalid OP length");
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", true,
+ "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
+ 0);
+ db_raw_sql(dbc, "UPDATE auc_3g SET op = 'BeefedCafeFaceAcedAddedDecadeFe'");
+ ASSERT_SEL_AUD(imsi0, -EIO, id);
+
+ /* Invalid OPC length */
+ comment("Set auth data, 3G only, with invalid OPC length");
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", false,
+ "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
+ 0);
+ db_raw_sql(dbc, "UPDATE auc_3g SET opc = 'BeefedCafeFaceAcedAddedDecadeFe'");
+ ASSERT_SEL_AUD(imsi0, -EIO, id);
+
+
+ comment("Delete subscriber");
+ ASSERT_RC(db_subscr_delete_by_id(dbc, id), 0);
+ comment_end();
+}
+
+static void test_subscr_sqn(void)
{
int64_t id;
@@ -822,6 +922,50 @@ static void test_subscr_sqn()
comment_end();
}
+static void test_ind(void)
+{
+ comment_start();
+
+#define ASSERT_IND(VLR, IND) do { \
+ unsigned int ind; \
+ struct osmo_cni_peer_id vlr; \
+ OSMO_ASSERT(!osmo_cni_peer_id_set_str(&vlr, OSMO_CNI_PEER_ID_IPA_NAME, VLR)); \
+ ASSERT_RC(db_ind(dbc, &vlr, &ind), 0); \
+ fprintf(stderr, "%s ind = %u\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len), ind); \
+ if (ind != (IND)) \
+ fprintf(stderr, " ERROR: expected " #IND "\n"); \
+ } while (0)
+#define IND_DEL(VLR) do { \
+ struct osmo_cni_peer_id vlr; \
+ OSMO_ASSERT(!osmo_cni_peer_id_set_str(&vlr, OSMO_CNI_PEER_ID_IPA_NAME, VLR)); \
+ ASSERT_RC(db_ind_del(dbc, &vlr), 0); \
+ fprintf(stderr, "%s ind deleted\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len)); \
+ } while (0)
+
+ ASSERT_IND("msc-23", 1);
+ ASSERT_IND("sgsn-11", 2);
+ ASSERT_IND("msc-42", 3);
+ ASSERT_IND("sgsn-22", 4);
+ ASSERT_IND("msc-0x17", 5);
+ ASSERT_IND("sgsn-0xaa", 6);
+ ASSERT_IND("msc-42", 3);
+ ASSERT_IND("sgsn-22", 4);
+ ASSERT_IND("msc-0x17", 5);
+ ASSERT_IND("sgsn-0xaa", 6);
+ ASSERT_IND("sgsn-0xbb", 7);
+ ASSERT_IND("msc-0x2a", 8);
+ ASSERT_IND("msc-42", 3);
+ ASSERT_IND("sgsn-22", 4);
+ ASSERT_IND("msc-23", 1);
+ ASSERT_IND("sgsn-11", 2);
+
+ IND_DEL("msc-0x17"); /* dropped IND == 5 */
+ ASSERT_IND("msc-0x2a", 8); /* known CS remains where it is */
+ ASSERT_IND("any-unknown", 9); /* new VLR takes a new IND from the end */
+
+ comment_end();
+}
+
static struct {
bool verbose;
} cmdline_opts = {
@@ -884,9 +1028,13 @@ int main(int argc, char **argv)
handle_options(argc, argv);
osmo_init_logging2(ctx, &hlr_log_info);
- log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
+ log_set_print_filename2(osmo_stderr_target,
+ cmdline_opts.verbose ?
+ LOG_FILENAME_BASENAME :
+ LOG_FILENAME_NONE);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
@@ -900,9 +1048,12 @@ int main(int argc, char **argv)
test_subscr_create_update_sel_delete();
test_subscr_aud();
+ test_subscr_aud_invalid_len();
test_subscr_sqn();
+ test_ind();
printf("Done\n");
+ db_close(dbc);
return 0;
}
diff --git a/tests/db/db_test.err b/tests/db/db_test.err
index 4dc77e8..dee85e0 100644
--- a/tests/db/db_test.err
+++ b/tests/db/db_test.err
@@ -27,7 +27,7 @@ struct hlr_subscriber {
.imsi = '123456789000002',
}
-db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
+db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
DAUC IMSI='123456789000000': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
@@ -36,10 +36,10 @@ struct hlr_subscriber {
.imsi = '123456789000000',
}
-db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
+db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
-db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
+db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
@@ -48,10 +48,10 @@ struct hlr_subscriber {
.imsi = '123456789000001',
}
-db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
+db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
-db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
+db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
@@ -64,25 +64,21 @@ db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG
DAUC Cannot create subscriber: invalid IMSI: '123456789 000003'
db_subscr_get_by_imsi(dbc, "123456789000003", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000003': No such subscriber
db_subscr_create(dbc, "123456789000002123456", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
DAUC Cannot create subscriber: invalid IMSI: '123456789000002123456'
db_subscr_get_by_imsi(dbc, "123456789000002123456", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000002123456': No such subscriber
db_subscr_create(dbc, "foobar123", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
DAUC Cannot create subscriber: invalid IMSI: 'foobar123'
db_subscr_get_by_imsi(dbc, "foobar123", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='foobar123': No such subscriber
db_subscr_create(dbc, "123", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
DAUC Cannot create subscriber: invalid IMSI: '123'
db_subscr_get_by_imsi(dbc, "123", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123': No such subscriber
db_subscr_create(dbc, short_imsi, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
@@ -142,7 +138,6 @@ struct hlr_subscriber {
}
db_subscr_get_by_msisdn(dbc, "54321012345678912345678", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='54321012345678912345678': No such subscriber
db_subscr_update_msisdn_by_imsi(dbc, imsi0, "543 21") --> -EINVAL
DAUC IMSI='123456789000000': Cannot update subscriber: invalid MSISDN: '543 21'
@@ -155,7 +150,6 @@ struct hlr_subscriber {
}
db_subscr_get_by_msisdn(dbc, "543 21", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='543 21': No such subscriber
db_subscr_update_msisdn_by_imsi(dbc, imsi0, "foobar123") --> -EINVAL
DAUC IMSI='123456789000000': Cannot update subscriber: invalid MSISDN: 'foobar123'
@@ -168,7 +162,6 @@ struct hlr_subscriber {
}
db_subscr_get_by_msisdn(dbc, "foobar123", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='foobar123': No such subscriber
db_subscr_update_msisdn_by_imsi(dbc, imsi0, "5") --> 0
@@ -187,7 +180,6 @@ struct hlr_subscriber {
}
db_subscr_get_by_msisdn(dbc, "54321", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='54321': No such subscriber
db_subscr_update_msisdn_by_imsi(dbc, imsi0, "543210123456789") --> 0
@@ -216,7 +208,6 @@ struct hlr_subscriber {
}
db_subscr_get_by_msisdn(dbc, "5432101234567891", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='5432101234567891': No such subscriber
--- Check if subscriber exists (by MSISDN)
@@ -232,13 +223,11 @@ db_subscr_update_msisdn_by_imsi(dbc, unknown_imsi, "99") --> -ENOENT
DAUC Cannot update MSISDN: no such subscriber: IMSI='999999999'
db_subscr_get_by_msisdn(dbc, "99", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='99': No such subscriber
db_subscr_update_msisdn_by_imsi(dbc, "foobar", "99") --> -ENOENT
DAUC Cannot update MSISDN: no such subscriber: IMSI='foobar'
db_subscr_get_by_msisdn(dbc, "99", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: MSISDN='99': No such subscriber
--- Set valid / invalid IMEI
@@ -265,7 +254,6 @@ struct hlr_subscriber {
}
db_subscr_get_by_imei(dbc, "123456789012345", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMEI=123456789012345: No such subscriber
--- Set the same IMEI again
@@ -286,7 +274,6 @@ struct hlr_subscriber {
db_subscr_update_imei_by_imsi(dbc, imsi0, NULL) --> 0
db_subscr_get_by_imei(dbc, "12345678901234", &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMEI=12345678901234: No such subscriber
--- Set / unset nam_cs and nam_ps
@@ -424,7 +411,6 @@ db_subscr_nam(dbc, unknown_imsi, false, false) --> -ENOENT
DAUC Cannot disable CS: no such subscriber: IMSI='999999999'
db_subscr_get_by_imsi(dbc, unknown_imsi, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='999999999': No such subscriber
db_subscr_nam(dbc, "foobar", false, true) --> -ENOENT
DAUC Cannot disable PS: no such subscriber: IMSI='foobar'
@@ -435,7 +421,7 @@ DAUC Cannot disable CS: no such subscriber: IMSI='foobar'
--- Record LU for PS and CS (SGSN and VLR names)
-db_subscr_lu(dbc, id0, "5952", true) --> 0
+db_subscr_lu_str(dbc, id0, "5952", true) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -445,7 +431,7 @@ struct hlr_subscriber {
.sgsn_number = '5952',
}
-db_subscr_lu(dbc, id0, "712", false) --> 0
+db_subscr_lu_str(dbc, id0, "712", false) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -459,7 +445,7 @@ struct hlr_subscriber {
--- Record LU for PS and CS (SGSN and VLR names) *again*
-db_subscr_lu(dbc, id0, "111", true) --> 0
+db_subscr_lu_str(dbc, id0, "111", true) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -470,7 +456,7 @@ struct hlr_subscriber {
.sgsn_number = '111',
}
-db_subscr_lu(dbc, id0, "111", true) --> 0
+db_subscr_lu_str(dbc, id0, "111", true) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -481,7 +467,7 @@ struct hlr_subscriber {
.sgsn_number = '111',
}
-db_subscr_lu(dbc, id0, "222", false) --> 0
+db_subscr_lu_str(dbc, id0, "222", false) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -492,7 +478,7 @@ struct hlr_subscriber {
.sgsn_number = '111',
}
-db_subscr_lu(dbc, id0, "222", false) --> 0
+db_subscr_lu_str(dbc, id0, "222", false) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -506,7 +492,7 @@ struct hlr_subscriber {
--- Unset LU info for PS and CS (SGSN and VLR names)
-db_subscr_lu(dbc, id0, "", true) --> 0
+db_subscr_lu_str(dbc, id0, "", true) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -516,7 +502,7 @@ struct hlr_subscriber {
.vlr_number = '222',
}
-db_subscr_lu(dbc, id0, "", false) --> 0
+db_subscr_lu_str(dbc, id0, "", false) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -525,9 +511,9 @@ struct hlr_subscriber {
.msisdn = '543210123456789',
}
-db_subscr_lu(dbc, id0, "111", true) --> 0
+db_subscr_lu_str(dbc, id0, "111", true) --> 0
-db_subscr_lu(dbc, id0, "222", false) --> 0
+db_subscr_lu_str(dbc, id0, "222", false) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -538,7 +524,7 @@ struct hlr_subscriber {
.sgsn_number = '111',
}
-db_subscr_lu(dbc, id0, NULL, true) --> 0
+db_subscr_lu_str(dbc, id0, NULL, true) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -548,7 +534,7 @@ struct hlr_subscriber {
.vlr_number = '222',
}
-db_subscr_lu(dbc, id0, NULL, false) --> 0
+db_subscr_lu_str(dbc, id0, NULL, false) --> 0
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
struct hlr_subscriber {
@@ -560,14 +546,13 @@ struct hlr_subscriber {
--- Record LU for non-existent ID
-db_subscr_lu(dbc, 99999, "5952", true) --> -ENOENT
+db_subscr_lu_str(dbc, 99999, "5952", true) --> -ENOENT
DAUC Cannot update SGSN number for subscriber ID=99999: no such subscriber
-db_subscr_lu(dbc, 99999, "712", false) --> -ENOENT
+db_subscr_lu_str(dbc, 99999, "712", false) --> -ENOENT
DAUC Cannot update VLR number for subscriber ID=99999: no such subscriber
db_subscr_get_by_id(dbc, 99999, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: ID=99999: No such subscriber
--- Purge and un-purge PS and CS
@@ -698,13 +683,11 @@ db_subscr_purge(dbc, unknown_imsi, true, true) --> -ENOENT
DAUC Cannot purge PS: no such subscriber: IMSI='999999999'
db_subscr_get_by_imsi(dbc, unknown_imsi, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='999999999': No such subscriber
db_subscr_purge(dbc, unknown_imsi, true, false) --> -ENOENT
DAUC Cannot purge CS: no such subscriber: IMSI='999999999'
db_subscr_get_by_imsi(dbc, unknown_imsi, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='999999999': No such subscriber
--- Delete non-existent / invalid IDs
@@ -728,7 +711,6 @@ struct hlr_subscriber {
db_subscr_delete_by_id(dbc, id0) --> 0
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
db_subscr_delete_by_id(dbc, id0) --> -ENOENT
DAUC Cannot delete: no such subscriber: ID=1
@@ -742,7 +724,6 @@ struct hlr_subscriber {
db_subscr_delete_by_id(dbc, id1) --> 0
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000001': No such subscriber
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
struct hlr_subscriber {
@@ -753,7 +734,6 @@ struct hlr_subscriber {
db_subscr_delete_by_id(dbc, id2) --> 0
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000002': No such subscriber
db_subscr_get_by_imsi(dbc, short_imsi, &g_subscr) --> 0
struct hlr_subscriber {
@@ -764,7 +744,6 @@ struct hlr_subscriber {
db_subscr_delete_by_id(dbc, id_short) --> 0
db_subscr_get_by_imsi(dbc, short_imsi, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456': No such subscriber
--- Create and delete subscribers with non-default nam_cs and nam_ps
@@ -814,7 +793,7 @@ db_get_auth_data(dbc, unknown_imsi, &g_aud2g, &g_aud3g, &g_id) --> -2
DAUC IMSI='999999999': No such subscriber
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -2
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -2
DAUC IMSI='123456789000000': No such subscriber
@@ -828,12 +807,12 @@ struct hlr_subscriber {
.imsi = '123456789000000',
}
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -845,14 +824,14 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v1,
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
}
3G: none
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> 3
DAUC IMSI='123456789000000': No 3G Auth Data
DAUC IMSI='123456789000000': Calling to generate 3 vectors
DAUC IMSI='123456789000000': Generated 3 vectors
@@ -862,7 +841,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v1,
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
@@ -874,7 +853,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v2, "BeadedBe
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v2,
.u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade',
@@ -886,21 +865,21 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "DeafBedd
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf',
}
3G: none
-db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
- .algo = XOR,
+ .algo = XOR-2G,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
3G: none
@@ -910,37 +889,37 @@ DAUC IMSI='123456789000000': No 3G Auth Data
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> 0
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> -ENOENT
-db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
- .algo = XOR,
+ .algo = XOR-2G,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
3G: none
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, "f000000000000f00000000000f000000")) --> 0
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -953,7 +932,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -963,7 +942,7 @@ DAUC IMSI='123456789000000': No 2G Auth Data
.u.umts.ind_bitlen = 5,
}
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> 3
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': Calling to generate 3 vectors
DAUC IMSI='123456789000000': Generated 3 vectors
@@ -975,7 +954,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -991,7 +970,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d',
@@ -1006,7 +985,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1022,7 +1001,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
@@ -1037,12 +1016,12 @@ DAUC IMSI='123456789000000': No 2G Auth Data
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)) --> 0
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -1054,7 +1033,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
@@ -1064,7 +1043,7 @@ DAUC IMSI='123456789000000': No 2G Auth Data
.u.umts.ind_bitlen = 5,
}
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> 3
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': Calling to generate 3 vectors
DAUC IMSI='123456789000000': Generated 3 vectors
@@ -1072,12 +1051,12 @@ DAUC IMSI='123456789000000': Updating SQN=0 in DB
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, "asdfasdfasd", false, "asdfasdfasdf", 99999)) --> 0
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -1090,12 +1069,12 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCaf
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1105,7 +1084,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
.u.umts.ind_bitlen = 5,
}
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> 3
DAUC IMSI='123456789000000': Calling to generate 3 vectors
DAUC IMSI='123456789000000': Generated 3 vectors
DAUC IMSI='123456789000000': Updating SQN=0 in DB
@@ -1118,12 +1097,12 @@ DAUC Cannot update auth tokens: Unknown auth algo: 99999
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1133,17 +1112,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
.u.umts.ind_bitlen = 5,
}
-db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1153,17 +1132,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
.u.umts.ind_bitlen = 5,
}
-db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")) --> -EINVAL
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")) --> -EINVAL
DAUC Cannot update auth tokens: Invalid KI: 'f00'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1178,12 +1157,12 @@ DAUC Cannot update auth tokens: auth algo not suited for 2G: MILENAGE
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1198,12 +1177,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: '0f000000000000f00000000000f0000
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1218,12 +1197,12 @@ DAUC Cannot update auth tokens: Invalid K: '000000000000f00000000000f000000'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1238,12 +1217,12 @@ DAUC Cannot update auth tokens: Invalid ind_bitlen: 29
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1258,12 +1237,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: 'X000000000000f00000000000f00000
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1278,12 +1257,12 @@ DAUC Cannot update auth tokens: Invalid K: 'f000000000000 f00000000000 f000000'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
-2G: struct osmo_sub_auth_data {
+2G: struct osmo_sub_auth_data2 {
.type = GSM,
.algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
}
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1305,7 +1284,6 @@ struct hlr_subscriber {
db_subscr_delete_by_id(dbc, id) --> 0
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
--- Re-add subscriber and verify auth data didn't come back
@@ -1318,26 +1296,110 @@ struct hlr_subscriber {
.imsi = '123456789000000',
}
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
db_subscr_delete_by_id(dbc, id) --> 0
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
-db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -2
+db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL, false) --> -2
DAUC IMSI='123456789000000': No such subscriber
===== test_subscr_aud: SUCCESS
+===== test_subscr_aud_invalid_len
+
+--- Create subscriber
+
+db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
+
+db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
+struct hlr_subscriber {
+ .id = 1,
+ .imsi = '123456789000000',
+}
+
+
+--- Set auth data, 2G only, with invalid Ki length
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")) --> 0
+
+raw SQL: UPDATE auc_2g SET ki = '0123456789abcdef0123456789abcde'
+sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
+
+sqlite3_step(stmt) --> SQLITE_DONE
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
+DAUC IMSI='123456789000000': Error reading Ki, expected min length 16 but has length 15
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+
+--- Remove 2G auth data
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> 0
+
+
+--- Set auth data, 3G only, with invalid K length
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
+
+raw SQL: UPDATE auc_3g SET k = 'C01ffedC1cadaeAc1d1f1edAcac1aB0'
+sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
+
+sqlite3_step(stmt) --> SQLITE_DONE
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': Error reading K, expected min length 16 but has length 15
+
+
+
+--- Set auth data, 3G only, with invalid OP length
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
+
+raw SQL: UPDATE auc_3g SET op = 'BeefedCafeFaceAcedAddedDecadeFe'
+sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
+
+sqlite3_step(stmt) --> SQLITE_DONE
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': Error reading OP, expected min length 16 but has length 15
+
+
+
+--- Set auth data, 3G only, with invalid OPC length
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", false, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
+
+raw SQL: UPDATE auc_3g SET opc = 'BeefedCafeFaceAcedAddedDecadeFe'
+sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
+
+sqlite3_step(stmt) --> SQLITE_DONE
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': Error reading OPC, expected min length 16 but has length 15
+
+
+
+--- Delete subscriber
+
+db_subscr_delete_by_id(dbc, id) --> 0
+
+===== test_subscr_aud_invalid_len: SUCCESS
+
+
===== test_subscr_sqn
--- Set SQN for unknown subscriber
@@ -1346,13 +1408,11 @@ db_update_sqn(dbc, 99, 999) --> -ENOENT
DAUC Cannot update SQN for subscriber ID=99: no auc_3g entry for such subscriber
db_subscr_get_by_id(dbc, 99, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: ID=99: No such subscriber
db_update_sqn(dbc, 9999, 99) --> -ENOENT
DAUC Cannot update SQN for subscriber ID=9999: no auc_3g entry for such subscriber
db_subscr_get_by_id(dbc, 9999, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: ID=9999: No such subscriber
--- Create subscriber
@@ -1365,7 +1425,7 @@ struct hlr_subscriber {
.imsi = '123456789000000',
}
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -1376,7 +1436,7 @@ DAUC IMSI='123456789000000': No 3G Auth Data
db_update_sqn(dbc, id, 123) --> -ENOENT
DAUC Cannot update SQN for subscriber ID=1: no auc_3g entry for such subscriber
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -1384,7 +1444,7 @@ DAUC IMSI='123456789000000': No 3G Auth Data
db_update_sqn(dbc, id, 543) --> -ENOENT
DAUC Cannot update SQN for subscriber ID=1: no auc_3g entry for such subscriber
-db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': No 3G Auth Data
@@ -1398,7 +1458,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1417,7 +1477,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1435,7 +1495,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1453,7 +1513,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1474,7 +1534,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1490,7 +1550,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1508,7 +1568,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1526,7 +1586,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data
2G: none
-3G: struct osmo_sub_auth_data {
+3G: struct osmo_sub_auth_data2 {
.type = UMTS,
.algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1550,7 +1610,86 @@ struct hlr_subscriber {
db_subscr_delete_by_id(dbc, id) --> 0
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
-DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
===== test_subscr_sqn: SUCCESS
+
+===== test_ind
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-23\0" ind = 1
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-11\0" ind = 2
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-42\0" ind = 3
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-22\0" ind = 4
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x17\0" ind = 5
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-0xaa\0" ind = 6
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-42\0" ind = 3
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-22\0" ind = 4
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x17\0" ind = 5
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-0xaa\0" ind = 6
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-0xbb\0" ind = 7
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x2a\0" ind = 8
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-42\0" ind = 3
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-22\0" ind = 4
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-23\0" ind = 1
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-11\0" ind = 2
+
+db_ind_del(dbc, &vlr) --> 0
+
+"msc-0x17\0" ind deleted
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x2a\0" ind = 8
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"any-unknown\0" ind = 9
+
+===== test_ind: SUCCESS
+
diff --git a/tests/db_upgrade/Makefile.am b/tests/db_upgrade/Makefile.am
new file mode 100644
index 0000000..79136c9
--- /dev/null
+++ b/tests/db_upgrade/Makefile.am
@@ -0,0 +1,14 @@
+EXTRA_DIST = \
+ db_upgrade_test.sh \
+ db_upgrade_test.err \
+ db_upgrade_test.ok \
+ hlr_db_v0.sql \
+ osmo-hlr.cfg \
+ create_subscribers.vty \
+ $(NULL)
+
+update_exp:
+ $(srcdir)/db_upgrade_test.sh $(srcdir) $(builddir) >"$(srcdir)/db_upgrade_test.ok" 2>"$(srcdir)/db_upgrade_test.err"
+
+upgrade-equivalence-test:
+ $(srcdir)/db_upgrade_test.sh $(srcdir) $(builddir) do-equivalence-test
diff --git a/tests/db_upgrade/create_subscribers.vty b/tests/db_upgrade/create_subscribers.vty
new file mode 100644
index 0000000..6e30b37
--- /dev/null
+++ b/tests/db_upgrade/create_subscribers.vty
@@ -0,0 +1,47 @@
+OsmoHLR> enable
+OsmoHLR# subscriber imsi 123456789012345 create
+% Created subscriber 123456789012345
+ ID: 1
+ IMSI: 123456789012345
+ MSISDN: none
+OsmoHLR# subscriber imsi 123456789012345 update msisdn 098765432109876
+% Updated subscriber IMSI='123456789012345' to MSISDN='098765432109876'
+OsmoHLR# subscriber imsi 123456789012345 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
+OsmoHLR# subscriber imsi 123456789012345 update aud3g milenage k C01ffedC1cadaeAc1d1f1edAcac1aB0a opc CededEffacedAceFacedBadFadedBeef
+OsmoHLR# subscriber imsi 111111111 create
+% Created subscriber 111111111
+ ID: 2
+ IMSI: 111111111
+ MSISDN: none
+OsmoHLR# subscriber imsi 222222222 create
+% Created subscriber 222222222
+ ID: 3
+ IMSI: 222222222
+ MSISDN: none
+OsmoHLR# subscriber imsi 222222222 update msisdn 22222
+% Updated subscriber IMSI='222222222' to MSISDN='22222'
+OsmoHLR# subscriber imsi 333333 create
+% Created subscriber 333333
+ ID: 4
+ IMSI: 333333
+ MSISDN: none
+OsmoHLR# subscriber imsi 333333 update msisdn 3
+% Updated subscriber IMSI='333333' to MSISDN='3'
+OsmoHLR# subscriber imsi 333333 update aud2g comp128v2 ki 33333333333333333333333333333333
+OsmoHLR# subscriber imsi 444444444444444 create
+% Created subscriber 444444444444444
+ ID: 5
+ IMSI: 444444444444444
+ MSISDN: none
+OsmoHLR# subscriber imsi 444444444444444 update msisdn 4444
+% Updated subscriber IMSI='444444444444444' to MSISDN='4444'
+OsmoHLR# subscriber imsi 444444444444444 update aud3g milenage k 44444444444444444444444444444444 op 44444444444444444444444444444444
+OsmoHLR# subscriber imsi 5555555 create
+% Created subscriber 5555555
+ ID: 6
+ IMSI: 5555555
+ MSISDN: none
+OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
+% Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
+OsmoHLR# subscriber imsi 5555555 update aud2g xor-2g ki 55555555555555555555555555555555
+OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555
diff --git a/tests/db_upgrade/create_subscribers_step2.sql b/tests/db_upgrade/create_subscribers_step2.sql
new file mode 100644
index 0000000..7933e25
--- /dev/null
+++ b/tests/db_upgrade/create_subscribers_step2.sql
@@ -0,0 +1,6 @@
+update subscriber set vlr_number = 'MSC-1' where id = 1;
+update subscriber set ms_purged_cs = 1 where id = 2;
+update subscriber set ms_purged_ps = 1 where id = 3;
+update subscriber set nam_cs = 0 where id = 4;
+update subscriber set nam_ps = 0 where id = 5;
+update subscriber set nam_cs = 0, nam_ps = 0 where id = 6;
diff --git a/tests/gsup_server/gsup_server_test.err b/tests/db_upgrade/db_upgrade_test.err
index e69de29..e69de29 100644
--- a/tests/gsup_server/gsup_server_test.err
+++ b/tests/db_upgrade/db_upgrade_test.err
diff --git a/tests/db_upgrade/db_upgrade_test.ok b/tests/db_upgrade/db_upgrade_test.ok
new file mode 100644
index 0000000..c719498
--- /dev/null
+++ b/tests/db_upgrade/db_upgrade_test.ok
@@ -0,0 +1,184 @@
+Creating db in schema version 0
+
+Version 0 db:
+
+Table: auc_2g
+name|type|notnull|dflt_value|pk
+algo_id_2g|INTEGER|1||0
+ki|VARCHAR(32)|1||0
+subscriber_id|INTEGER|0||1
+
+Table auc_2g contents:
+algo_id_2g|ki|subscriber_id
+1|BeefedCafeFaceAcedAddedDecadeFee|1
+2|33333333333333333333333333333333|4
+6|55555555555555555555555555555555|6
+
+Table: auc_3g
+name|type|notnull|dflt_value|pk
+algo_id_3g|INTEGER|1||0
+ind_bitlen|INTEGER|1|5|0
+k|VARCHAR(32)|1||0
+op|VARCHAR(32)|0||0
+opc|VARCHAR(32)|0||0
+sqn|INTEGER|1|0|0
+subscriber_id|INTEGER|0||1
+
+Table auc_3g contents:
+algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
+5|5|C01ffedC1cadaeAc1d1f1edAcac1aB0a||CededEffacedAceFacedBadFadedBeef|0|1
+5|5|44444444444444444444444444444444|44444444444444444444444444444444||0|5
+5|5|55555555555555555555555555555555||55555555555555555555555555555555|0|6
+
+Table: subscriber
+name|type|notnull|dflt_value|pk
+ggsn_number|VARCHAR(15)|0||0
+gmlc_number|VARCHAR(15)|0||0
+hlr_number|VARCHAR(15)|0||0
+id|INTEGER|0||1
+imeisv|VARCHAR|0||0
+imsi|VARCHAR(15)|1||0
+lmsi|INTEGER|0||0
+ms_purged_cs|BOOLEAN|1|0|0
+ms_purged_ps|BOOLEAN|1|0|0
+msisdn|VARCHAR(15)|0||0
+nam_cs|BOOLEAN|1|1|0
+nam_ps|BOOLEAN|1|1|0
+periodic_lu_tmr|INTEGER|0||0
+periodic_rau_tau_tmr|INTEGER|0||0
+sgsn_address|VARCHAR|0||0
+sgsn_number|VARCHAR(15)|0||0
+smsc_number|VARCHAR(15)|0||0
+vlr_number|VARCHAR(15)|0||0
+
+Table subscriber contents:
+ggsn_number|gmlc_number|hlr_number|id|imeisv|imsi|lmsi|ms_purged_cs|ms_purged_ps|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|smsc_number|vlr_number
+|||1||123456789012345||0|0|098765432109876|1|1||||||MSC-1
+|||2||111111111||1|0||1|1||||||
+|||3||222222222||0|1|22222|1|1||||||
+|||4||333333||0|0|3|0|1||||||
+|||5||444444444444444||0|0|4444|1|0||||||
+|||6||5555555||0|0|55555555555555|0|0||||||
+
+Table: subscriber_apn
+name|type|notnull|dflt_value|pk
+apn|VARCHAR(256)|1||0
+subscriber_id|INTEGER|0||0
+
+Table subscriber_apn contents:
+
+Table: subscriber_multi_msisdn
+name|type|notnull|dflt_value|pk
+msisdn|VARCHAR(15)|1||0
+subscriber_id|INTEGER|0||0
+
+Table subscriber_multi_msisdn contents:
+
+Launching osmo-hlr to upgrade db:
+osmo-hlr --database $db --db-upgrade --db-check --config-file $srcdir/osmo-hlr.cfg
+rc = 0
+DMAIN hlr starting
+DDB using database: <PATH>test.db
+DDB Database <PATH>test.db' has HLR DB schema version 0
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 1
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 2
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7
+DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
+
+Resulting db:
+
+Table: auc_2g
+name|type|notnull|dflt_value|pk
+algo_id_2g|INTEGER|1||0
+ki|VARCHAR(32)|1||0
+subscriber_id|INTEGER|0||1
+
+Table auc_2g contents:
+algo_id_2g|ki|subscriber_id
+1|BeefedCafeFaceAcedAddedDecadeFee|1
+2|33333333333333333333333333333333|4
+6|55555555555555555555555555555555|6
+
+Table: auc_3g
+name|type|notnull|dflt_value|pk
+algo_id_3g|INTEGER|1||0
+ind_bitlen|INTEGER|1|5|0
+k|VARCHAR(64)|1||0
+op|VARCHAR(64)|0||0
+opc|VARCHAR(64)|0||0
+sqn|INTEGER|1|0|0
+subscriber_id|INTEGER|0||1
+
+Table auc_3g contents:
+algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
+5|5|C01ffedC1cadaeAc1d1f1edAcac1aB0a||CededEffacedAceFacedBadFadedBeef|0|1
+5|5|44444444444444444444444444444444|44444444444444444444444444444444||0|5
+5|5|55555555555555555555555555555555||55555555555555555555555555555555|0|6
+
+Table: ind
+name|type|notnull|dflt_value|pk
+ind|INTEGER|0||1
+vlr|TEXT|1||0
+
+Table ind contents:
+
+Table: subscriber
+name|type|notnull|dflt_value|pk
+ggsn_number|VARCHAR(15)|0||0
+gmlc_number|VARCHAR(15)|0||0
+id|INTEGER|0||1
+imei|VARCHAR(14)|0||0
+imeisv|VARCHAR|0||0
+imsi|VARCHAR(15)|1||0
+last_lu_seen|TIMESTAMP|0|NULL|0
+last_lu_seen_ps|TIMESTAMP|0|NULL|0
+lmsi|INTEGER|0||0
+ms_purged_cs|BOOLEAN|1|0|0
+ms_purged_ps|BOOLEAN|1|0|0
+msc_number|VARCHAR(15)|0||0
+msisdn|VARCHAR(15)|0||0
+nam_cs|BOOLEAN|1|1|0
+nam_ps|BOOLEAN|1|1|0
+periodic_lu_tmr|INTEGER|0||0
+periodic_rau_tau_tmr|INTEGER|0||0
+sgsn_address|VARCHAR|0||0
+sgsn_number|VARCHAR(15)|0||0
+sgsn_via_proxy|VARCHAR|0||0
+smsc_number|VARCHAR(15)|0||0
+vlr_number|VARCHAR(15)|0||0
+vlr_via_proxy|VARCHAR|0||0
+
+Table subscriber contents:
+ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_seen|last_lu_seen_ps|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|sgsn_via_proxy|smsc_number|vlr_number|vlr_via_proxy
+||1|||123456789012345||||0|0||098765432109876|1|1|||||||MSC-1|
+||2|||111111111||||1|0|||1|1||||||||
+||3|||222222222||||0|1||22222|1|1||||||||
+||4|||333333||||0|0||3|0|1||||||||
+||5|||444444444444444||||0|0||4444|1|0||||||||
+||6|||5555555||||0|0||55555555555555|0|0||||||||
+
+Table: subscriber_apn
+name|type|notnull|dflt_value|pk
+apn|VARCHAR(256)|1||0
+subscriber_id|INTEGER|0||0
+
+Table subscriber_apn contents:
+
+Table: subscriber_multi_msisdn
+name|type|notnull|dflt_value|pk
+msisdn|VARCHAR(15)|1||0
+subscriber_id|INTEGER|0||0
+
+Table subscriber_multi_msisdn contents:
+
+Verify that osmo-hlr can open it:
+osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
+rc = 0
+DMAIN hlr starting
+DDB using database: <PATH>test.db
+DDB Database <PATH>test.db' has HLR DB schema version 7
+DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
diff --git a/tests/db_upgrade/db_upgrade_test.sh b/tests/db_upgrade/db_upgrade_test.sh
new file mode 100755
index 0000000..8e2b498
--- /dev/null
+++ b/tests/db_upgrade/db_upgrade_test.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+srcdir="${1:-.}"
+builddir="${2:-.}"
+do_equivalence_test="$3"
+
+set -e
+
+db="$builddir/test.db"
+osmo_hlr="$builddir/../../src/osmo-hlr"
+cfg="$srcdir/osmo-hlr.cfg"
+
+dump_sorted_schema(){
+ db_file="$1"
+ tables="$(sqlite3 -batch -noheader "$db_file" "SELECT name FROM sqlite_master WHERE type = 'table' order by name")"
+ for table in $tables; do
+ echo
+ echo "Table: $table"
+ sqlite3 -batch -header "$db_file" "SELECT name,type,\"notnull\",dflt_value,pk FROM PRAGMA_TABLE_INFO('$table') order by name;"
+ echo
+ echo "Table $table contents:"
+ columns="$(sqlite3 -batch -noheader "$db_file" "SELECT name FROM PRAGMA_TABLE_INFO('$table') order by name;")"
+ sqlite3 -batch -header "$db_file" "SELECT $(echo $columns | sed 's/ /,/g') from $table;"
+ done
+}
+
+rm -f "$db"
+echo "Creating db in schema version 0"
+sqlite3 -batch "$db" < "$srcdir/hlr_db_v0.sql"
+
+echo
+echo "Version 0 db:"
+dump_sorted_schema "$db"
+
+set +e
+
+echo
+echo "Launching osmo-hlr to upgrade db:"
+echo osmo-hlr --database '$db' --db-upgrade --db-check --config-file '$srcdir/osmo-hlr.cfg'
+"$osmo_hlr" --database "$db" --db-upgrade --db-check --config-file "$cfg" >log 2>&1
+echo "rc = $?"
+cat log | sed 's@[^ "]*/@<PATH>@g'
+
+echo
+echo "Resulting db:"
+dump_sorted_schema "$db"
+
+echo
+echo "Verify that osmo-hlr can open it:"
+echo osmo-hlr --database '$db' --db-check --config-file '$srcdir/osmo-hlr.cfg'
+"$osmo_hlr" --database "$db" --db-check --config-file "$cfg" >log 2>&1
+echo "rc = $?"
+cat log | sed 's@[^ "]*/@<PATH>@g'
+
+if [ -n "$do_equivalence_test" ]; then
+ # this part requires osmo_interact_vty.py, so this test is not part of the normal run
+ set -e -x
+ mint_db="$builddir/mint.db"
+ rm -f "$mint_db"
+
+ osmo_verify_transcript_vty.py -v \
+ -n OsmoHLR -p 4258 \
+ -r "$osmo_hlr -c $cfg -l $mint_db" \
+ "$srcdir/create_subscribers.vty"
+ sqlite3 -batch "$mint_db" < "$srcdir/create_subscribers_step2.sql"
+
+ set +x
+ test_dump="$builddir/test.dump"
+ mint_dump="$builddir/mint.dump"
+
+ dump_sorted_schema "$db" > "$test_dump"
+ dump_sorted_schema "$mint_db" > "$mint_dump"
+
+ echo
+ echo "Newly created sorted schema is:"
+ cat "$mint_dump"
+ echo
+ echo "Diff to upgraded schema:"
+ diff -u "$mint_dump" "$test_dump"
+ echo "rc=$?"
+fi
+
+rm -f log
+rm -f "$db"
diff --git a/tests/db_upgrade/hlr_db_v0.sql b/tests/db_upgrade/hlr_db_v0.sql
new file mode 100644
index 0000000..eb24eb5
--- /dev/null
+++ b/tests/db_upgrade/hlr_db_v0.sql
@@ -0,0 +1,80 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE subscriber (
+-- OsmoHLR's DB scheme is modelled roughly after TS 23.008 version 13.3.0
+ id INTEGER PRIMARY KEY,
+ -- Chapter 2.1.1.1
+ imsi VARCHAR(15) UNIQUE NOT NULL,
+ -- Chapter 2.1.2
+ msisdn VARCHAR(15) UNIQUE,
+ -- Chapter 2.2.3: Most recent / current IMEI
+ imeisv VARCHAR,
+ -- Chapter 2.4.5
+ vlr_number VARCHAR(15),
+ -- Chapter 2.4.6
+ hlr_number VARCHAR(15),
+ -- Chapter 2.4.8.1
+ sgsn_number VARCHAR(15),
+ -- Chapter 2.13.10
+ sgsn_address VARCHAR,
+ -- Chapter 2.4.8.2
+ ggsn_number VARCHAR(15),
+ -- Chapter 2.4.9.2
+ gmlc_number VARCHAR(15),
+ -- Chapter 2.4.23
+ smsc_number VARCHAR(15),
+ -- Chapter 2.4.24
+ periodic_lu_tmr INTEGER,
+ -- Chapter 2.13.115
+ periodic_rau_tau_tmr INTEGER,
+ -- Chapter 2.1.1.2: network access mode
+ nam_cs BOOLEAN NOT NULL DEFAULT 1,
+ nam_ps BOOLEAN NOT NULL DEFAULT 1,
+ -- Chapter 2.1.8
+ lmsi INTEGER,
+ -- The below purged flags might not even be stored non-volatile,
+ -- refer to TS 23.012 Chapter 3.6.1.4
+ -- Chapter 2.7.5
+ ms_purged_cs BOOLEAN NOT NULL DEFAULT 0,
+ -- Chapter 2.7.6
+ ms_purged_ps BOOLEAN NOT NULL DEFAULT 0
+);
+INSERT INTO subscriber VALUES(1,'123456789012345','098765432109876',NULL,'MSC-1',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,1,NULL,0,0);
+INSERT INTO subscriber VALUES(2,'111111111',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,1,NULL,1,0);
+INSERT INTO subscriber VALUES(3,'222222222','22222',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,1,NULL,0,1);
+INSERT INTO subscriber VALUES(4,'333333','3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,NULL,0,0);
+INSERT INTO subscriber VALUES(5,'444444444444444','4444',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,NULL,0,0);
+INSERT INTO subscriber VALUES(6,'5555555','55555555555555',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,NULL,0,0);
+CREATE TABLE subscriber_apn (
+ subscriber_id INTEGER, -- subscriber.id
+ apn VARCHAR(256) NOT NULL
+);
+CREATE TABLE subscriber_multi_msisdn (
+-- Chapter 2.1.3
+ subscriber_id INTEGER, -- subscriber.id
+ msisdn VARCHAR(15) NOT NULL
+);
+CREATE TABLE auc_2g (
+ subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
+ algo_id_2g INTEGER NOT NULL, -- enum osmo_auth_algo value
+ ki VARCHAR(32) NOT NULL -- hex string: subscriber's secret key (128bit)
+);
+INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee');
+INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333');
+INSERT INTO auc_2g VALUES(6,6,'55555555555555555555555555555555');
+CREATE TABLE auc_3g (
+ subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
+ algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
+ k VARCHAR(32) NOT NULL, -- hex string: subscriber's secret key (128bit)
+ op VARCHAR(32), -- hex string: operator's secret key (128bit)
+ opc VARCHAR(32), -- hex string: derived from OP and K (128bit)
+ sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
+ -- nr of index bits at lower SQN end
+ ind_bitlen INTEGER NOT NULL DEFAULT 5
+);
+INSERT INTO auc_3g VALUES(1,5,'C01ffedC1cadaeAc1d1f1edAcac1aB0a',NULL,'CededEffacedAceFacedBadFadedBeef',0,5);
+INSERT INTO auc_3g VALUES(5,5,'44444444444444444444444444444444','44444444444444444444444444444444',NULL,0,5);
+INSERT INTO auc_3g VALUES(6,5,'55555555555555555555555555555555',NULL,'55555555555555555555555555555555',0,5);
+CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi)
+;
+COMMIT;
diff --git a/tests/db_upgrade/osmo-hlr.cfg b/tests/db_upgrade/osmo-hlr.cfg
new file mode 100644
index 0000000..7fb12c1
--- /dev/null
+++ b/tests/db_upgrade/osmo-hlr.cfg
@@ -0,0 +1,6 @@
+log stderr
+ logging level db notice
+ logging print category-hex 0
+ logging print file 0
+ logging print category 1
+ logging color 0
diff --git a/tests/gsup/Makefile.am b/tests/gsup/Makefile.am
index 907aae8..04bc51a 100644
--- a/tests/gsup/Makefile.am
+++ b/tests/gsup/Makefile.am
@@ -1,14 +1,11 @@
AM_CPPFLAGS = \
$(all_includes) \
- -I$(top_srcdir)/src \
+ -I$(top_srcdir)/include \
$(NULL)
AM_CFLAGS = \
- -Wall \
- -ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@@ -20,7 +17,7 @@ EXTRA_DIST = \
gsup_test.err \
$(NULL)
-noinst_PROGRAMS = \
+check_PROGRAMS = \
gsup_test \
$(NULL)
@@ -29,12 +26,9 @@ gsup_test_SOURCES = \
$(NULL)
gsup_test_LDADD = \
- $(top_srcdir)/src/luop.c \
- $(top_srcdir)/src/gsup_server.c \
- $(top_srcdir)/src/gsup_router.c \
+ $(top_builddir)/src/gsupclient/libosmo-gsup-client.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
- $(LIBOSMOABIS_LIBS) \
$(NULL)
.PHONY: update_exp
diff --git a/tests/gsup/gsup_test.c b/tests/gsup/gsup_test.c
index 41865d2..88c6093 100644
--- a/tests/gsup/gsup_test.c
+++ b/tests/gsup/gsup_test.c
@@ -22,52 +22,74 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/application.h>
-#include <osmocom/gsm/gsup.h>
+#include <osmocom/gsupclient/gsup_req.h>
-#include "logging.h"
-#include "luop.h"
+void *ctx = NULL;
-struct osmo_gsup_server;
-
-/* override osmo_gsup_addr_send() to not actually send anything. */
-int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
- const uint8_t *addr, size_t addrlen,
- struct msgb *msg)
+static void test_gsup_make_response(void)
{
- LOGP(DMAIN, LOGL_DEBUG, "%s\n", msgb_hexdump(msg));
- msgb_free(msg);
- return 0;
-}
+ char *source_name = "incoming-source-name";
+ char *destination_name = "preset-destination-name";
+ uint8_t sm_rp_mr = 23;
+ uint8_t other_sm_rp_mr = 17;
+ struct osmo_gsup_message rx = {
+ .message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST,
+ .imsi = "1234567",
+ .message_class = OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT,
+ .source_name = (uint8_t*)source_name,
+ .source_name_len = strlen(source_name) + 1,
+ .sm_rp_mr = &sm_rp_mr,
+ .session_id = 42,
+ .session_state = OSMO_GSUP_SESSION_STATE_BEGIN,
+ };
+ struct osmo_gsup_message nonempty = {
+ .message_type = OSMO_GSUP_MSGT_ROUTING_ERROR,
+ .imsi = "987654321",
+ .message_class = OSMO_GSUP_MESSAGE_CLASS_INTER_MSC,
+ .destination_name = (uint8_t*)destination_name,
+ .destination_name_len = strlen(destination_name) + 1,
+ .sm_rp_mr = &other_sm_rp_mr,
+ .session_id = 11,
+ .session_state = OSMO_GSUP_SESSION_STATE_END,
+ };
+ void *name_ctx = talloc_named_const(ctx, 0, __func__);
+ int error;
+ int final;
+ char *nonempty_str;
+ int rc;
-int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
- struct hlr_subscriber *subscr)
-{
- return 0;
-}
+ printf("\n%s()\n", __func__);
+ printf("rx = %s\n", osmo_gsup_message_to_str_c(name_ctx, &rx));
-/* Verify that the internally allocated msgb is large enough */
-void test_gsup_tx_insert_subscr_data()
-{
- struct lu_operation luop = {
- .state = LU_S_LU_RECEIVED,
- .subscr = {
- .imsi = "123456789012345",
- .msisdn = "987654321098765",
- .nam_cs = true,
- .nam_ps = true,
- },
- .is_ps = true,
- };
+ printf("\nwriting to an empty struct osmo_gsup_message should populate values as needed:\n");
+ for (error = 0; error <= 1; error++) {
+ for (final = 0; final <= 1; final++) {
+ struct osmo_gsup_message target = {};
+ printf("- args (error=%d, final=%d)\n", error, final);
+ rc = osmo_gsup_make_response(&target, &rx, error, final);
+ printf(" %s\n", osmo_gsup_message_to_str_c(name_ctx, &target));
+ printf(" rc = %d\n", rc);
+ }
+ }
- lu_op_tx_insert_subscr_data(&luop);
+ printf("\nwriting to an already populated struct osmo_gsup_message, should have no effect:\n");
+ nonempty_str = osmo_gsup_message_to_str_c(name_ctx, &nonempty);
+ for (error = 0; error <= 1; error++) {
+ for (final = 0; final <= 1; final++) {
+ struct osmo_gsup_message target = nonempty;
+ char *result;
+ printf("- args (error=%d, final=%d)\n", error, final);
+ rc = osmo_gsup_make_response(&target, &rx, error, final);
+ result = osmo_gsup_message_to_str_c(name_ctx, &target);
+ printf(" %s\n", result);
+ if (strcmp(result, nonempty_str))
+ printf(" ERROR: expected: %s\n", nonempty_str);
+ printf(" rc = %d\n", rc);
+ }
+ }
}
const struct log_info_cat default_categories[] = {
- [DMAIN] = {
- .name = "DMAIN",
- .description = "Main Program",
- .enabled = 1, .loglevel = LOGL_DEBUG,
- },
};
static struct log_info info = {
@@ -77,14 +99,14 @@ static struct log_info info = {
int main(int argc, char **argv)
{
- void *ctx = talloc_named_const(NULL, 0, "gsup_test");
+ ctx = talloc_named_const(NULL, 0, "gsup_test");
osmo_init_logging2(ctx, &info);
- log_set_print_filename(osmo_stderr_target, 0);
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
- test_gsup_tx_insert_subscr_data();
+ test_gsup_make_response();
printf("Done.\n");
return EXIT_SUCCESS;
diff --git a/tests/gsup/gsup_test.err b/tests/gsup/gsup_test.err
index 0aeae30..e69de29 100644
--- a/tests/gsup/gsup_test.err
+++ b/tests/gsup/gsup_test.err
@@ -1,2 +0,0 @@
-DMAIN 10 01 08 21 43 65 87 09 21 43 f5 08 09 08 89 67 45 23 01 89 67 f5 05 07 10 01 01 12 02 01 2a 28 01 01
-DMAIN LU OP state change: LU RECEIVED -> ISD SENT
diff --git a/tests/gsup/gsup_test.ok b/tests/gsup/gsup_test.ok
index 619c561..0899633 100644
--- a/tests/gsup/gsup_test.ok
+++ b/tests/gsup/gsup_test.ok
@@ -1 +1,32 @@
+
+test_gsup_make_response()
+rx = Subscriber-Management OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST: imsi="1234567" source_name="incoming-source-name\0" session_id=42 session_state=BEGIN sm_rp_mr=23
+
+writing to an empty struct osmo_gsup_message should populate values as needed:
+- args (error=0, final=0)
+ Subscriber-Management OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: imsi="1234567" destination_name="incoming-source-name\0" session_id=42 session_state=CONTINUE sm_rp_mr=23
+ rc = 0
+- args (error=0, final=1)
+ Subscriber-Management OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: imsi="1234567" destination_name="incoming-source-name\0" session_id=42 session_state=END sm_rp_mr=23
+ rc = 0
+- args (error=1, final=0)
+ Subscriber-Management OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR: imsi="1234567" destination_name="incoming-source-name\0" session_id=42 session_state=CONTINUE sm_rp_mr=23
+ rc = 0
+- args (error=1, final=1)
+ Subscriber-Management OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR: imsi="1234567" destination_name="incoming-source-name\0" session_id=42 session_state=END sm_rp_mr=23
+ rc = 0
+
+writing to an already populated struct osmo_gsup_message, should have no effect:
+- args (error=0, final=0)
+ Inter-MSC OSMO_GSUP_MSGT_ROUTING_ERROR: imsi="987654321" destination_name="preset-destination-name\0" session_id=11 session_state=END sm_rp_mr=17
+ rc = 15
+- args (error=0, final=1)
+ Inter-MSC OSMO_GSUP_MSGT_ROUTING_ERROR: imsi="987654321" destination_name="preset-destination-name\0" session_id=11 session_state=END sm_rp_mr=17
+ rc = 15
+- args (error=1, final=0)
+ Inter-MSC OSMO_GSUP_MSGT_ROUTING_ERROR: imsi="987654321" destination_name="preset-destination-name\0" session_id=11 session_state=END sm_rp_mr=17
+ rc = 15
+- args (error=1, final=1)
+ Inter-MSC OSMO_GSUP_MSGT_ROUTING_ERROR: imsi="987654321" destination_name="preset-destination-name\0" session_id=11 session_state=END sm_rp_mr=17
+ rc = 15
Done.
diff --git a/tests/gsup_server/Makefile.am b/tests/gsup_server/Makefile.am
deleted file mode 100644
index 686ce37..0000000
--- a/tests/gsup_server/Makefile.am
+++ /dev/null
@@ -1,41 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/src \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- -ggdb3 \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(NULL)
-
-AM_LDFLAGS = \
- -no-install \
- $(NULL)
-
-EXTRA_DIST = \
- gsup_server_test.ok \
- gsup_server_test.err \
- $(NULL)
-
-noinst_PROGRAMS = \
- gsup_server_test \
- $(NULL)
-
-gsup_server_test_SOURCES = \
- gsup_server_test.c \
- $(NULL)
-
-gsup_server_test_LDADD = \
- $(top_srcdir)/src/gsup_server.c \
- $(top_srcdir)/src/gsup_router.c \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMOABIS_LIBS) \
- $(NULL)
-
-.PHONY: update_exp
-update_exp:
- $(builddir)/gsup_server_test >"$(srcdir)/gsup_server_test.ok" 2>"$(srcdir)/gsup_server_test.err"
diff --git a/tests/gsup_server/gsup_server_test.c b/tests/gsup_server/gsup_server_test.c
deleted file mode 100644
index cc475be..0000000
--- a/tests/gsup_server/gsup_server_test.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdio.h>
-#include <osmocom/core/utils.h>
-#include "gsup_server.h"
-
-#define comment_start() printf("\n===== %s\n", __func__)
-#define comment_end() printf("===== %s: SUCCESS\n\n", __func__)
-#define btw(fmt, args...) printf("\n" fmt "\n", ## args)
-
-#define VERBOSE_ASSERT(val, expect_op, fmt) \
- do { \
- printf(#val " == " fmt "\n", (val)); \
- OSMO_ASSERT((val) expect_op); \
- } while (0)
-
-void osmo_gsup_server_add_conn(struct llist_head *clients,
- struct osmo_gsup_conn *conn);
-
-static void test_add_conn(void)
-{
- struct llist_head _list;
- struct llist_head *clients = &_list;
- struct osmo_gsup_conn conn_inst[23] = {};
- struct osmo_gsup_conn *conn;
- unsigned int i;
-
- comment_start();
-
- INIT_LLIST_HEAD(clients);
-
- btw("Add 10 items");
- for (i = 0; i < 10; i++) {
- osmo_gsup_server_add_conn(clients, &conn_inst[i]);
- printf("conn_inst[%u].auc_3g_ind == %u\n", i, conn_inst[i].auc_3g_ind);
- OSMO_ASSERT(clients->next == &conn_inst[0].list);
- }
-
- btw("Expecting a list of 0..9");
- i = 0;
- llist_for_each_entry(conn, clients, list) {
- printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
- OSMO_ASSERT(conn->auc_3g_ind == i);
- OSMO_ASSERT(conn == &conn_inst[i]);
- i++;
- }
-
- btw("Punch two holes in the sequence in arbitrary order,"
- " a larger one from 2..4 and a single one at 7.");
- llist_del(&conn_inst[4].list);
- llist_del(&conn_inst[2].list);
- llist_del(&conn_inst[3].list);
- llist_del(&conn_inst[7].list);
-
- btw("Expecting a list of 0,1, 5,6, 8,9");
- i = 0;
- llist_for_each_entry(conn, clients, list) {
- printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
- i++;
- }
-
- btw("Add conns, expecting them to take the open slots");
- osmo_gsup_server_add_conn(clients, &conn_inst[12]);
- VERBOSE_ASSERT(conn_inst[12].auc_3g_ind, == 2, "%u");
-
- osmo_gsup_server_add_conn(clients, &conn_inst[13]);
- VERBOSE_ASSERT(conn_inst[13].auc_3g_ind, == 3, "%u");
-
- osmo_gsup_server_add_conn(clients, &conn_inst[14]);
- VERBOSE_ASSERT(conn_inst[14].auc_3g_ind, == 4, "%u");
-
- osmo_gsup_server_add_conn(clients, &conn_inst[17]);
- VERBOSE_ASSERT(conn_inst[17].auc_3g_ind, == 7, "%u");
-
- osmo_gsup_server_add_conn(clients, &conn_inst[18]);
- VERBOSE_ASSERT(conn_inst[18].auc_3g_ind, == 10, "%u");
-
- btw("Expecting a list of 0..10");
- i = 0;
- llist_for_each_entry(conn, clients, list) {
- printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
- OSMO_ASSERT(conn->auc_3g_ind == i);
- i++;
- }
-
- btw("Does it also work for the first item?");
- llist_del(&conn_inst[0].list);
-
- btw("Expecting a list of 1..10");
- i = 0;
- llist_for_each_entry(conn, clients, list) {
- printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
- OSMO_ASSERT(conn->auc_3g_ind == i + 1);
- i++;
- }
-
- btw("Add another conn, should take auc_3g_ind == 0");
- osmo_gsup_server_add_conn(clients, &conn_inst[20]);
- VERBOSE_ASSERT(conn_inst[20].auc_3g_ind, == 0, "%u");
-
- btw("Expecting a list of 0..10");
- i = 0;
- llist_for_each_entry(conn, clients, list) {
- printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
- OSMO_ASSERT(conn->auc_3g_ind == i);
- i++;
- }
-
- btw("If a client reconnects, it will (likely) get the same auc_3g_ind");
- VERBOSE_ASSERT(conn_inst[5].auc_3g_ind, == 5, "%u");
- llist_del(&conn_inst[5].list);
- conn_inst[5].auc_3g_ind = 423;
- osmo_gsup_server_add_conn(clients, &conn_inst[5]);
- VERBOSE_ASSERT(conn_inst[5].auc_3g_ind, == 5, "%u");
-
- comment_end();
-}
-
-int main(int argc, char **argv)
-{
- printf("test_gsup_server.c\n");
-
- test_add_conn();
-
- printf("Done\n");
- return 0;
-}
diff --git a/tests/gsup_server/gsup_server_test.ok b/tests/gsup_server/gsup_server_test.ok
deleted file mode 100644
index 80d944c..0000000
--- a/tests/gsup_server/gsup_server_test.ok
+++ /dev/null
@@ -1,94 +0,0 @@
-test_gsup_server.c
-
-===== test_add_conn
-
-Add 10 items
-conn_inst[0].auc_3g_ind == 0
-conn_inst[1].auc_3g_ind == 1
-conn_inst[2].auc_3g_ind == 2
-conn_inst[3].auc_3g_ind == 3
-conn_inst[4].auc_3g_ind == 4
-conn_inst[5].auc_3g_ind == 5
-conn_inst[6].auc_3g_ind == 6
-conn_inst[7].auc_3g_ind == 7
-conn_inst[8].auc_3g_ind == 8
-conn_inst[9].auc_3g_ind == 9
-
-Expecting a list of 0..9
-conn[0].auc_3g_ind == 0
-conn[1].auc_3g_ind == 1
-conn[2].auc_3g_ind == 2
-conn[3].auc_3g_ind == 3
-conn[4].auc_3g_ind == 4
-conn[5].auc_3g_ind == 5
-conn[6].auc_3g_ind == 6
-conn[7].auc_3g_ind == 7
-conn[8].auc_3g_ind == 8
-conn[9].auc_3g_ind == 9
-
-Punch two holes in the sequence in arbitrary order, a larger one from 2..4 and a single one at 7.
-
-Expecting a list of 0,1, 5,6, 8,9
-conn[0].auc_3g_ind == 0
-conn[1].auc_3g_ind == 1
-conn[2].auc_3g_ind == 5
-conn[3].auc_3g_ind == 6
-conn[4].auc_3g_ind == 8
-conn[5].auc_3g_ind == 9
-
-Add conns, expecting them to take the open slots
-conn_inst[12].auc_3g_ind == 2
-conn_inst[13].auc_3g_ind == 3
-conn_inst[14].auc_3g_ind == 4
-conn_inst[17].auc_3g_ind == 7
-conn_inst[18].auc_3g_ind == 10
-
-Expecting a list of 0..10
-conn[0].auc_3g_ind == 0
-conn[1].auc_3g_ind == 1
-conn[2].auc_3g_ind == 2
-conn[3].auc_3g_ind == 3
-conn[4].auc_3g_ind == 4
-conn[5].auc_3g_ind == 5
-conn[6].auc_3g_ind == 6
-conn[7].auc_3g_ind == 7
-conn[8].auc_3g_ind == 8
-conn[9].auc_3g_ind == 9
-conn[10].auc_3g_ind == 10
-
-Does it also work for the first item?
-
-Expecting a list of 1..10
-conn[0].auc_3g_ind == 1
-conn[1].auc_3g_ind == 2
-conn[2].auc_3g_ind == 3
-conn[3].auc_3g_ind == 4
-conn[4].auc_3g_ind == 5
-conn[5].auc_3g_ind == 6
-conn[6].auc_3g_ind == 7
-conn[7].auc_3g_ind == 8
-conn[8].auc_3g_ind == 9
-conn[9].auc_3g_ind == 10
-
-Add another conn, should take auc_3g_ind == 0
-conn_inst[20].auc_3g_ind == 0
-
-Expecting a list of 0..10
-conn[0].auc_3g_ind == 0
-conn[1].auc_3g_ind == 1
-conn[2].auc_3g_ind == 2
-conn[3].auc_3g_ind == 3
-conn[4].auc_3g_ind == 4
-conn[5].auc_3g_ind == 5
-conn[6].auc_3g_ind == 6
-conn[7].auc_3g_ind == 7
-conn[8].auc_3g_ind == 8
-conn[9].auc_3g_ind == 9
-conn[10].auc_3g_ind == 10
-
-If a client reconnects, it will (likely) get the same auc_3g_ind
-conn_inst[5].auc_3g_ind == 5
-conn_inst[5].auc_3g_ind == 5
-===== test_add_conn: SUCCESS
-
-Done
diff --git a/tests/mslookup/Makefile.am b/tests/mslookup/Makefile.am
new file mode 100644
index 0000000..5c53a02
--- /dev/null
+++ b/tests/mslookup/Makefile.am
@@ -0,0 +1,72 @@
+AM_CPPFLAGS = \
+ $(all_includes) \
+ -I$(top_srcdir)/include \
+ $(NULL)
+
+AM_CFLAGS = \
+ -Wall \
+ -ggdb3 \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(NULL)
+
+AM_LDFLAGS = \
+ -no-install \
+ $(NULL)
+
+EXTRA_DIST = \
+ mdns_test.err \
+ mslookup_client_mdns_test.err \
+ mslookup_client_test.err \
+ mslookup_test.err \
+ $(NULL)
+
+check_PROGRAMS = \
+ mdns_test \
+ mslookup_client_test \
+ mslookup_test \
+ $(NULL)
+
+mslookup_test_SOURCES = \
+ mslookup_test.c \
+ $(NULL)
+mslookup_test_LDADD = \
+ $(top_builddir)/src/mslookup/libosmo-mslookup.la \
+ $(LIBOSMOGSM_LIBS) \
+ $(NULL)
+
+mslookup_client_test_SOURCES = \
+ mslookup_client_test.c \
+ $(NULL)
+mslookup_client_test_LDADD = \
+ $(top_builddir)/src/mslookup/libosmo-mslookup.la \
+ $(LIBOSMOGSM_LIBS) \
+ $(NULL)
+
+mdns_test_SOURCES = \
+ mdns_test.c \
+ $(NULL)
+mdns_test_LDADD = \
+ $(top_builddir)/src/mslookup/libosmo-mslookup.la \
+ $(LIBOSMOGSM_LIBS) \
+ $(NULL)
+
+if ENABLE_MSLOOKUP_CLIENT_MDNS_TEST
+check_PROGRAMS += mslookup_client_mdns_test
+
+mslookup_client_mdns_test_SOURCES = \
+ mslookup_client_mdns_test.c \
+ $(NULL)
+mslookup_client_mdns_test_LDADD = \
+ $(top_builddir)/src/mslookup/libosmo-mslookup.la \
+ $(LIBOSMOGSM_LIBS) \
+ $(NULL)
+endif
+
+.PHONY: update_exp
+update_exp:
+ for i in $(check_PROGRAMS); do \
+ echo "Updating $$i.err"; \
+ $(builddir)/$$i 2>"$(srcdir)/$$i.err"; \
+ done
diff --git a/tests/mslookup/mdns_test.c b/tests/mslookup/mdns_test.c
new file mode 100644
index 0000000..e9fc1fb
--- /dev/null
+++ b/tests/mslookup/mdns_test.c
@@ -0,0 +1,459 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/mslookup/mdns_rfc.h>
+#include <osmocom/mslookup/mdns_msg.h>
+
+struct qname_enc_dec_test {
+ const char *domain;
+ const char *qname;
+ size_t qname_max_len; /* default: strlen(qname) + 1 */
+};
+
+#define PRINT_HDR(hdr, name) \
+ fprintf(stderr, "header %s:\n" \
+ ".id = %i\n" \
+ ".qr = %i\n" \
+ ".opcode = %x\n" \
+ ".aa = %i\n" \
+ ".tc = %i\n" \
+ ".rd = %i\n" \
+ ".ra = %i\n" \
+ ".z = %x\n" \
+ ".rcode = %x\n" \
+ ".qdcount = %u\n" \
+ ".ancount = %u\n" \
+ ".nscount = %u\n" \
+ ".arcount = %u\n", \
+ name, hdr.id, hdr.qr, hdr.opcode, hdr.aa, hdr.tc, hdr.rd, hdr.ra, hdr.z, hdr.rcode, hdr.qdcount, \
+ hdr.ancount, hdr.nscount, hdr.arcount)
+
+static const struct osmo_mdns_rfc_header header_enc_dec_test_data[] = {
+ {
+ /* Typical use case for mslookup */
+ .id = 1337,
+ .qdcount = 1,
+ },
+ {
+ /* Fill out everything */
+ .id = 42,
+ .qr = 1,
+ .opcode = 0x02,
+ .aa = 1,
+ .tc = 1,
+ .rd = 1,
+ .ra = 1,
+ .z = 0x02,
+ .rcode = 0x03,
+ .qdcount = 1234,
+ .ancount = 1111,
+ .nscount = 2222,
+ .arcount = 3333,
+ },
+};
+
+void test_enc_dec_rfc_header(void)
+{
+ int i;
+
+ fprintf(stderr, "-- %s --\n", __func__);
+ for (i = 0; i< ARRAY_SIZE(header_enc_dec_test_data); i++) {
+ const struct osmo_mdns_rfc_header in = header_enc_dec_test_data[i];
+ struct osmo_mdns_rfc_header out = {0};
+ struct msgb *msg = msgb_alloc(4096, "dns_test");
+
+ PRINT_HDR(in, "in");
+ osmo_mdns_rfc_header_encode(msg, &in);
+ fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
+ assert(osmo_mdns_rfc_header_decode(msgb_data(msg), msgb_length(msg), &out) == 0);
+ PRINT_HDR(out, "out");
+
+ fprintf(stderr, "in (hexdump): %s\n", osmo_hexdump((unsigned char *)&in, sizeof(in)));
+ fprintf(stderr, "out (hexdump): %s\n", osmo_hexdump((unsigned char *)&out, sizeof(out)));
+ assert(memcmp(&in, &out, sizeof(in)) == 0);
+
+ fprintf(stderr, "=> OK\n\n");
+ msgb_free(msg);
+ }
+}
+
+void test_enc_dec_rfc_header_einval(void)
+{
+ struct osmo_mdns_rfc_header out = {0};
+ struct msgb *msg = msgb_alloc(4096, "dns_test");
+ fprintf(stderr, "-- %s --\n", __func__);
+
+ assert(osmo_mdns_rfc_header_decode(msgb_data(msg), 11, &out) == -EINVAL);
+ fprintf(stderr, "=> OK\n\n");
+
+ msgb_free(msg);
+}
+
+#define PRINT_QST(qst, name) \
+ fprintf(stderr, "question %s:\n" \
+ ".domain = %s\n" \
+ ".qtype = %i\n" \
+ ".qclass = %i\n", \
+ name, (qst)->domain, (qst)->qtype, (qst)->qclass)
+
+static const struct osmo_mdns_rfc_question question_enc_dec_test_data[] = {
+ {
+ .domain = "hlr.1234567.imsi",
+ .qtype = OSMO_MDNS_RFC_RECORD_TYPE_ALL,
+ .qclass = OSMO_MDNS_RFC_CLASS_IN,
+ },
+ {
+ .domain = "hlr.1234567.imsi",
+ .qtype = OSMO_MDNS_RFC_RECORD_TYPE_A,
+ .qclass = OSMO_MDNS_RFC_CLASS_ALL,
+ },
+ {
+ .domain = "hlr.1234567.imsi",
+ .qtype = OSMO_MDNS_RFC_RECORD_TYPE_AAAA,
+ .qclass = OSMO_MDNS_RFC_CLASS_ALL,
+ },
+};
+
+void test_enc_dec_rfc_question(void *ctx)
+{
+ int i;
+
+ fprintf(stderr, "-- %s --\n", __func__);
+ for (i = 0; i< ARRAY_SIZE(question_enc_dec_test_data); i++) {
+ const struct osmo_mdns_rfc_question in = question_enc_dec_test_data[i];
+ struct osmo_mdns_rfc_question *out;
+ struct msgb *msg = msgb_alloc(4096, "dns_test");
+
+ PRINT_QST(&in, "in");
+ assert(osmo_mdns_rfc_question_encode(msg, &in) == 0);
+ fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
+ out = osmo_mdns_rfc_question_decode(ctx, msgb_data(msg), msgb_length(msg));
+ assert(out);
+ PRINT_QST(out, "out");
+
+ if (strcmp(in.domain, out->domain) != 0)
+ fprintf(stderr, "=> ERROR: domain does not match\n");
+ else if (in.qtype != out->qtype)
+ fprintf(stderr, "=> ERROR: qtype does not match\n");
+ else if (in.qclass != out->qclass)
+ fprintf(stderr, "=> ERROR: qclass does not match\n");
+ else
+ fprintf(stderr, "=> OK\n");
+
+ fprintf(stderr, "\n");
+ msgb_free(msg);
+ talloc_free(out);
+ }
+}
+
+void test_enc_dec_rfc_question_null(void *ctx)
+{
+ uint8_t data[5] = {0};
+
+ fprintf(stderr, "-- %s --\n", __func__);
+ assert(osmo_mdns_rfc_question_decode(ctx, data, sizeof(data)) == NULL);
+ fprintf(stderr, "=> OK\n\n");
+}
+
+#define PRINT_REC(rec, name) \
+ fprintf(stderr, "question %s:\n" \
+ ".domain = %s\n" \
+ ".type = %i\n" \
+ ".class = %i\n" \
+ ".ttl = %i\n" \
+ ".rdlength = %i\n" \
+ ".rdata = %s\n", \
+ name, (rec)->domain, (rec)->type, (rec)->class, (rec)->ttl, (rec)->rdlength, \
+ osmo_quote_str((char *)(rec)->rdata, (rec)->rdlength))
+
+static const struct osmo_mdns_rfc_record record_enc_dec_test_data[] = {
+ {
+ .domain = "hlr.1234567.imsi",
+ .type = OSMO_MDNS_RFC_RECORD_TYPE_A,
+ .class = OSMO_MDNS_RFC_CLASS_IN,
+ .ttl = 1234,
+ .rdlength = 9,
+ .rdata = (uint8_t *)"10.42.2.1",
+ },
+};
+
+void test_enc_dec_rfc_record(void *ctx)
+{
+ int i;
+
+ fprintf(stderr, "-- %s --\n", __func__);
+ for (i=0; i< ARRAY_SIZE(record_enc_dec_test_data); i++) {
+ const struct osmo_mdns_rfc_record in = record_enc_dec_test_data[i];
+ struct osmo_mdns_rfc_record *out;
+ struct msgb *msg = msgb_alloc(4096, "dns_test");
+ size_t record_len;
+
+ PRINT_REC(&in, "in");
+ assert(osmo_mdns_rfc_record_encode(msg, &in) == 0);
+ fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
+ out = osmo_mdns_rfc_record_decode(ctx, msgb_data(msg), msgb_length(msg), &record_len);
+ fprintf(stderr, "record_len: %lu\n", record_len);
+ assert(out);
+ PRINT_REC(out, "out");
+
+ if (strcmp(in.domain, out->domain) != 0)
+ fprintf(stderr, "=> ERROR: domain does not match\n");
+ else if (in.type != out->type)
+ fprintf(stderr, "=> ERROR: type does not match\n");
+ else if (in.class != out->class)
+ fprintf(stderr, "=> ERROR: class does not match\n");
+ else if (in.ttl != out->ttl)
+ fprintf(stderr, "=> ERROR: ttl does not match\n");
+ else if (in.rdlength != out->rdlength)
+ fprintf(stderr, "=> ERROR: rdlength does not match\n");
+ else if (memcmp(in.rdata, out->rdata, in.rdlength) != 0)
+ fprintf(stderr, "=> ERROR: rdata does not match\n");
+ else
+ fprintf(stderr, "=> OK\n");
+
+ fprintf(stderr, "\n");
+ msgb_free(msg);
+ talloc_free(out);
+ }
+}
+
+static uint8_t ip_v4_n[] = {23, 42, 47, 11};
+static uint8_t ip_v6_n[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00};
+
+
+enum test_records {
+ RECORD_NONE,
+ RECORD_A,
+ RECORD_AAAA,
+ RECORD_TXT_AGE,
+ RECORD_TXT_PORT_444,
+ RECORD_TXT_PORT_666,
+ RECORD_TXT_INVALID_KEY,
+ RECORD_TXT_INVALID_NO_KEY_VALUE,
+ RECORD_INVALID,
+};
+struct result_from_answer_test {
+ const char *desc;
+ const enum test_records records[5];
+ bool error;
+ const struct osmo_mslookup_result res;
+};
+
+static void test_result_from_answer(void *ctx)
+{
+ void *print_ctx = talloc_named_const(ctx, 0, __func__);
+ struct osmo_sockaddr_str test_host_v4 = {.af = AF_INET, .port=444, .ip = "23.42.47.11"};
+ struct osmo_sockaddr_str test_host_v6 = {.af = AF_INET6, .port=666,
+ .ip = "1122:3344:5566:7788:99aa:bbcc:ddee:ff00"};
+ struct osmo_mslookup_result test_result_v4 = {.rc = OSMO_MSLOOKUP_RC_RESULT, .age = 3,
+ .host_v4 = test_host_v4};
+ struct osmo_mslookup_result test_result_v6 = {.rc = OSMO_MSLOOKUP_RC_RESULT, .age = 3,
+ .host_v6 = test_host_v6};
+ struct osmo_mslookup_result test_result_v4_v6 = {.rc = OSMO_MSLOOKUP_RC_RESULT, .age = 3,
+ .host_v4 = test_host_v4, .host_v6 = test_host_v6};
+ struct result_from_answer_test result_from_answer_data[] = {
+ {
+ .desc = "IPv4",
+ .records = {RECORD_TXT_AGE, RECORD_A, RECORD_TXT_PORT_444},
+ .res = test_result_v4
+ },
+ {
+ .desc = "IPv6",
+ .records = {RECORD_TXT_AGE, RECORD_AAAA, RECORD_TXT_PORT_666},
+ .res = test_result_v6
+ },
+ {
+ .desc = "IPv4 + IPv6",
+ .records = {RECORD_TXT_AGE, RECORD_A, RECORD_TXT_PORT_444, RECORD_AAAA, RECORD_TXT_PORT_666},
+ .res = test_result_v4_v6
+ },
+ {
+ .desc = "A twice",
+ .records = {RECORD_TXT_AGE, RECORD_A, RECORD_TXT_PORT_444, RECORD_A},
+ .error = true
+ },
+ {
+ .desc = "AAAA twice",
+ .records = {RECORD_TXT_AGE, RECORD_AAAA, RECORD_TXT_PORT_444, RECORD_AAAA},
+ .error = true
+ },
+ {
+ .desc = "invalid TXT: no key/value pair",
+ .records = {RECORD_TXT_AGE, RECORD_AAAA, RECORD_TXT_INVALID_NO_KEY_VALUE},
+ .error = true
+ },
+ {
+ .desc = "age twice",
+ .records = {RECORD_TXT_AGE, RECORD_TXT_AGE},
+ .error = true
+ },
+ {
+ .desc = "port as first record",
+ .records = {RECORD_TXT_PORT_444},
+ .error = true
+ },
+ {
+ .desc = "port without previous ip record",
+ .records = {RECORD_TXT_AGE, RECORD_TXT_PORT_444},
+ .error = true
+ },
+ {
+ .desc = "invalid TXT: invalid key",
+ .records = {RECORD_TXT_AGE, RECORD_AAAA, RECORD_TXT_INVALID_KEY},
+ .error = true
+ },
+ {
+ .desc = "unexpected record type",
+ .records = {RECORD_TXT_AGE, RECORD_INVALID},
+ .error = true
+ },
+ {
+ .desc = "missing record: age",
+ .records = {RECORD_A, RECORD_TXT_PORT_444},
+ .error = true
+ },
+ {
+ .desc = "missing record: port for ipv4",
+ .records = {RECORD_TXT_AGE, RECORD_A},
+ .error = true
+ },
+ {
+ .desc = "missing record: port for ipv4 #2",
+ .records = {RECORD_TXT_AGE, RECORD_AAAA, RECORD_TXT_PORT_666, RECORD_A},
+ .error = true
+ },
+ };
+ int i = 0;
+ int j = 0;
+
+ fprintf(stderr, "-- %s --\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(result_from_answer_data); i++) {
+ struct result_from_answer_test *t = &result_from_answer_data[i];
+ struct osmo_mdns_msg_answer ans = {0};
+ struct osmo_mslookup_result res = {0};
+ void *ctx_test = talloc_named_const(ctx, 0, t->desc);
+ bool is_error;
+
+ fprintf(stderr, "---\n");
+ fprintf(stderr, "test: %s\n", t->desc);
+ fprintf(stderr, "error: %s\n", t->error ? "true" : "false");
+ fprintf(stderr, "records:\n");
+ /* Build records list */
+ INIT_LLIST_HEAD(&ans.records);
+ for (j = 0; j < ARRAY_SIZE(t->records); j++) {
+ struct osmo_mdns_record *rec = NULL;
+
+ switch (t->records[j]) {
+ case RECORD_NONE:
+ break;
+ case RECORD_A:
+ fprintf(stderr, "- A 42.42.42.42\n");
+ rec = talloc_zero(ctx_test, struct osmo_mdns_record);
+ rec->type = OSMO_MDNS_RFC_RECORD_TYPE_A;
+ rec->data = ip_v4_n;
+ rec->length = sizeof(ip_v4_n);
+ break;
+ case RECORD_AAAA:
+ fprintf(stderr, "- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00\n");
+ rec = talloc_zero(ctx_test, struct osmo_mdns_record);
+ rec->type = OSMO_MDNS_RFC_RECORD_TYPE_AAAA;
+ rec->data = ip_v6_n;
+ rec->length = sizeof(ip_v6_n);
+ break;
+ case RECORD_TXT_AGE:
+ fprintf(stderr, "- TXT age=3\n");
+ rec = osmo_mdns_record_txt_keyval_encode(ctx_test, "age", "3");
+ break;
+ case RECORD_TXT_PORT_444:
+ fprintf(stderr, "- TXT port=444\n");
+ rec = osmo_mdns_record_txt_keyval_encode(ctx_test, "port", "444");
+ break;
+ case RECORD_TXT_PORT_666:
+ fprintf(stderr, "- TXT port=666\n");
+ rec = osmo_mdns_record_txt_keyval_encode(ctx_test, "port", "666");
+ break;
+ case RECORD_TXT_INVALID_KEY:
+ fprintf(stderr, "- TXT hello=world\n");
+ rec = osmo_mdns_record_txt_keyval_encode(ctx_test, "hello", "world");
+ break;
+ case RECORD_TXT_INVALID_NO_KEY_VALUE:
+ fprintf(stderr, "- TXT 12345\n");
+ rec = osmo_mdns_record_txt_keyval_encode(ctx_test, "12", "45");
+ rec->data[3] = '3';
+ break;
+ case RECORD_INVALID:
+ fprintf(stderr, "- (invalid)\n");
+ rec = talloc_zero(ctx, struct osmo_mdns_record);
+ rec->type = OSMO_MDNS_RFC_RECORD_TYPE_UNKNOWN;
+ break;
+ }
+
+ if (rec)
+ llist_add_tail(&rec->list, &ans.records);
+ }
+
+ /* Verify output */
+ is_error = (osmo_mdns_result_from_answer(&res, &ans) != 0);
+ if (t->error != is_error) {
+ fprintf(stderr, "got %s\n", is_error ? "error" : "no error");
+ OSMO_ASSERT(false);
+ }
+ if (!t->error) {
+ fprintf(stderr, "exp: %s\n", osmo_mslookup_result_name_c(print_ctx, NULL, &t->res));
+ fprintf(stderr, "res: %s\n", osmo_mslookup_result_name_c(print_ctx, NULL, &res));
+ OSMO_ASSERT(t->res.rc == res.rc);
+ OSMO_ASSERT(!osmo_sockaddr_str_cmp(&t->res.host_v4, &res.host_v4));
+ OSMO_ASSERT(!osmo_sockaddr_str_cmp(&t->res.host_v6, &res.host_v6));
+ OSMO_ASSERT(t->res.age == res.age);
+ OSMO_ASSERT(t->res.last == res.last);
+ }
+
+ talloc_free(ctx_test);
+ fprintf(stderr, "=> OK\n");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ void *ctx = talloc_named_const(NULL, 0, "main");
+ osmo_init_logging2(ctx, NULL);
+
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_print_level(osmo_stderr_target, 1);
+ log_set_print_category(osmo_stderr_target, 1);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_use_color(osmo_stderr_target, 0);
+
+ test_enc_dec_rfc_header();
+ test_enc_dec_rfc_header_einval();
+ test_enc_dec_rfc_question(ctx);
+ test_enc_dec_rfc_question_null(ctx);
+ test_enc_dec_rfc_record(ctx);
+
+ test_result_from_answer(ctx);
+
+ return 0;
+}
diff --git a/tests/mslookup/mdns_test.err b/tests/mslookup/mdns_test.err
new file mode 100644
index 0000000..0d650be
--- /dev/null
+++ b/tests/mslookup/mdns_test.err
@@ -0,0 +1,254 @@
+-- test_enc_dec_rfc_header --
+header in:
+.id = 1337
+.qr = 0
+.opcode = 0
+.aa = 0
+.tc = 0
+.rd = 0
+.ra = 0
+.z = 0
+.rcode = 0
+.qdcount = 1
+.ancount = 0
+.nscount = 0
+.arcount = 0
+encoded: 05 39 00 00 00 01 00 00 00 00 00 00
+header out:
+.id = 1337
+.qr = 0
+.opcode = 0
+.aa = 0
+.tc = 0
+.rd = 0
+.ra = 0
+.z = 0
+.rcode = 0
+.qdcount = 1
+.ancount = 0
+.nscount = 0
+.arcount = 0
+in (hexdump): 39 05 00 00 01 00 00 00 00 00 00 00
+out (hexdump): 39 05 00 00 01 00 00 00 00 00 00 00
+=> OK
+
+header in:
+.id = 42
+.qr = 1
+.opcode = 2
+.aa = 1
+.tc = 1
+.rd = 1
+.ra = 1
+.z = 2
+.rcode = 3
+.qdcount = 1234
+.ancount = 1111
+.nscount = 2222
+.arcount = 3333
+encoded: 00 2a 97 a3 04 d2 04 57 08 ae 0d 05
+header out:
+.id = 42
+.qr = 1
+.opcode = 2
+.aa = 1
+.tc = 1
+.rd = 1
+.ra = 1
+.z = 2
+.rcode = 3
+.qdcount = 1234
+.ancount = 1111
+.nscount = 2222
+.arcount = 3333
+in (hexdump): 2a 00 97 a3 d2 04 57 04 ae 08 05 0d
+out (hexdump): 2a 00 97 a3 d2 04 57 04 ae 08 05 0d
+=> OK
+
+-- test_enc_dec_rfc_header_einval --
+=> OK
+
+-- test_enc_dec_rfc_question --
+question in:
+.domain = hlr.1234567.imsi
+.qtype = 255
+.qclass = 1
+encoded: 03 68 6c 72 07 31 32 33 34 35 36 37 04 69 6d 73 69 00 00 ff 00 01
+question out:
+.domain = hlr.1234567.imsi
+.qtype = 255
+.qclass = 1
+=> OK
+
+question in:
+.domain = hlr.1234567.imsi
+.qtype = 1
+.qclass = 255
+encoded: 03 68 6c 72 07 31 32 33 34 35 36 37 04 69 6d 73 69 00 00 01 00 ff
+question out:
+.domain = hlr.1234567.imsi
+.qtype = 1
+.qclass = 255
+=> OK
+
+question in:
+.domain = hlr.1234567.imsi
+.qtype = 28
+.qclass = 255
+encoded: 03 68 6c 72 07 31 32 33 34 35 36 37 04 69 6d 73 69 00 00 1c 00 ff
+question out:
+.domain = hlr.1234567.imsi
+.qtype = 28
+.qclass = 255
+=> OK
+
+-- test_enc_dec_rfc_question_null --
+=> OK
+
+-- test_enc_dec_rfc_record --
+question in:
+.domain = hlr.1234567.imsi
+.type = 1
+.class = 1
+.ttl = 1234
+.rdlength = 9
+.rdata = "10.42.2.1"
+encoded: 03 68 6c 72 07 31 32 33 34 35 36 37 04 69 6d 73 69 00 00 01 00 01 00 00 04 d2 00 09 31 30 2e 34 32 2e 32 2e 31
+record_len: 37
+question out:
+.domain = hlr.1234567.imsi
+.type = 1
+.class = 1
+.ttl = 1234
+.rdlength = 9
+.rdata = "10.42.2.1"
+=> OK
+
+-- test_result_from_answer --
+---
+test: IPv4
+error: false
+records:
+- TXT age=3
+- A 42.42.42.42
+- TXT port=444
+exp: -> ipv4: 23.42.47.11:444 (age=3) (not-last)
+res: -> ipv4: 23.42.47.11:444 (age=3) (not-last)
+=> OK
+---
+test: IPv6
+error: false
+records:
+- TXT age=3
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+- TXT port=666
+exp: -> ipv6: [1122:3344:5566:7788:99aa:bbcc:ddee:ff00]:666 (age=3) (not-last)
+res: -> ipv6: [1122:3344:5566:7788:99aa:bbcc:ddee:ff00]:666 (age=3) (not-last)
+=> OK
+---
+test: IPv4 + IPv6
+error: false
+records:
+- TXT age=3
+- A 42.42.42.42
+- TXT port=444
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+- TXT port=666
+exp: -> ipv4: 23.42.47.11:444 -> ipv6: [1122:3344:5566:7788:99aa:bbcc:ddee:ff00]:666 (age=3) (not-last)
+res: -> ipv4: 23.42.47.11:444 -> ipv6: [1122:3344:5566:7788:99aa:bbcc:ddee:ff00]:666 (age=3) (not-last)
+=> OK
+---
+test: A twice
+error: true
+records:
+- TXT age=3
+- A 42.42.42.42
+- TXT port=444
+- A 42.42.42.42
+DLGLOBAL ERROR 'A' record found twice in mDNS answer
+=> OK
+---
+test: AAAA twice
+error: true
+records:
+- TXT age=3
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+- TXT port=444
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+DLGLOBAL ERROR 'AAAA' record found twice in mDNS answer
+=> OK
+---
+test: invalid TXT: no key/value pair
+error: true
+records:
+- TXT age=3
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+- TXT 12345
+DLGLOBAL ERROR failed to decode txt record
+=> OK
+---
+test: age twice
+error: true
+records:
+- TXT age=3
+- TXT age=3
+DLGLOBAL ERROR duplicate 'TXT' record for 'age'
+=> OK
+---
+test: port as first record
+error: true
+records:
+- TXT port=444
+DLGLOBAL ERROR 'TXT' record for 'port' without previous 'A' or 'AAAA' record
+=> OK
+---
+test: port without previous ip record
+error: true
+records:
+- TXT age=3
+- TXT port=444
+DLGLOBAL ERROR 'TXT' record for 'port' without previous 'A' or 'AAAA' record
+=> OK
+---
+test: invalid TXT: invalid key
+error: true
+records:
+- TXT age=3
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+- TXT hello=world
+DLGLOBAL ERROR unexpected key 'hello' in TXT record
+=> OK
+---
+test: unexpected record type
+error: true
+records:
+- TXT age=3
+- (invalid)
+DLGLOBAL ERROR unexpected record type
+=> OK
+---
+test: missing record: age
+error: true
+records:
+- A 42.42.42.42
+- TXT port=444
+DLGLOBAL ERROR missing resource records in mDNS answer
+=> OK
+---
+test: missing record: port for ipv4
+error: true
+records:
+- TXT age=3
+- A 42.42.42.42
+DLGLOBAL ERROR missing resource records in mDNS answer
+=> OK
+---
+test: missing record: port for ipv4 #2
+error: true
+records:
+- TXT age=3
+- AAAA 1122:3344:5566:7788:99aa:bbcc:ddee:ff00
+- TXT port=666
+- A 42.42.42.42
+DLGLOBAL ERROR missing resource records in mDNS answer
+=> OK
diff --git a/tests/mslookup/mslookup_client_mdns_test.c b/tests/mslookup/mslookup_client_mdns_test.c
new file mode 100644
index 0000000..274e1e7
--- /dev/null
+++ b/tests/mslookup/mslookup_client_mdns_test.c
@@ -0,0 +1,255 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/application.h>
+#include <osmocom/hlr/logging.h>
+#include <osmocom/mslookup/mslookup.h>
+#include <osmocom/mslookup/mslookup_client.h>
+#include <osmocom/mslookup/mslookup_client_mdns.h>
+#include <osmocom/mslookup/mdns.h>
+#include <osmocom/mslookup/mdns_sock.h>
+
+void *ctx = NULL;
+
+#define TEST_IP OSMO_MSLOOKUP_MDNS_IP4
+#define TEST_PORT OSMO_MSLOOKUP_MDNS_PORT
+#define TEST_DOMAIN_SUFFIX "mslookup_client_mdns_test.dgsm.osmocom.org"
+
+/*
+ * Test server (emulates the mDNS server in OsmoHLR) and client
+ */
+struct osmo_mdns_sock *server_mc;
+
+
+static void server_reply(struct osmo_mslookup_query *query, uint16_t packet_id)
+{
+ struct osmo_mslookup_result result = {0};
+ struct msgb *msg;
+
+ result.rc = OSMO_MSLOOKUP_RC_RESULT;
+ result.age = 3;
+ osmo_sockaddr_str_from_str(&result.host_v4, "42.42.42.42", 444);
+ osmo_sockaddr_str_from_str(&result.host_v6, "1122:3344:5566:7788:99aa:bbcc:ddee:ff00", 666);
+
+ msg = osmo_mdns_result_encode(ctx, packet_id, query, &result, TEST_DOMAIN_SUFFIX);
+ OSMO_ASSERT(msg);
+ OSMO_ASSERT(osmo_mdns_sock_send(server_mc, msg) == 0);
+}
+
+static int server_recv(struct osmo_fd *osmo_fd, unsigned int what)
+{
+ int n;
+ uint8_t buffer[1024];
+ uint16_t packet_id;
+ struct osmo_mslookup_query *query;
+
+ fprintf(stderr, "%s\n", __func__);
+
+ /* Parse the message and print it */
+ n = read(osmo_fd->fd, buffer, sizeof(buffer));
+ OSMO_ASSERT(n >= 0);
+
+ query = osmo_mdns_query_decode(ctx, buffer, n, &packet_id, TEST_DOMAIN_SUFFIX);
+ if (!query)
+ return -1; /* server receiving own answer is expected */
+
+ fprintf(stderr, "received request\n");
+ server_reply(query, packet_id);
+ talloc_free(query);
+ return n;
+}
+
+static void server_init(void)
+{
+ fprintf(stderr, "%s\n", __func__);
+ server_mc = osmo_mdns_sock_init(ctx, TEST_IP, TEST_PORT, server_recv, NULL, 0);
+ OSMO_ASSERT(server_mc);
+}
+
+static void server_stop(void)
+{
+ fprintf(stderr, "%s\n", __func__);
+ OSMO_ASSERT(server_mc);
+ osmo_mdns_sock_cleanup(server_mc);
+ server_mc = NULL;
+}
+
+struct osmo_mslookup_client* client;
+struct osmo_mslookup_client_method* client_method;
+
+static void client_init(void)
+{
+ fprintf(stderr, "%s\n", __func__);
+ client = osmo_mslookup_client_new(ctx);
+ OSMO_ASSERT(client);
+ client_method = osmo_mslookup_client_add_mdns(client, TEST_IP, TEST_PORT, 1337, TEST_DOMAIN_SUFFIX);
+ OSMO_ASSERT(client_method);
+}
+
+static void client_recv(struct osmo_mslookup_client *client, uint32_t request_handle,
+ const struct osmo_mslookup_query *query, const struct osmo_mslookup_result *result)
+{
+ char buf[256];
+ fprintf(stderr, "%s\n", __func__);
+ fprintf(stderr, "client_recv(): %s\n", osmo_mslookup_result_name_b(buf, sizeof(buf), query, result));
+
+ osmo_mslookup_client_request_cancel(client, request_handle);
+}
+
+static void client_query(void)
+{
+ struct osmo_mslookup_id id = {.type = OSMO_MSLOOKUP_ID_IMSI,
+ .imsi = "123456789012345"};
+ const struct osmo_mslookup_query query = {
+ .service = "gsup.hlr",
+ .id = id,
+ };
+ struct osmo_mslookup_query_handling handling = {
+ .result_timeout_milliseconds = 2000,
+ .result_cb = client_recv,
+ };
+
+ fprintf(stderr, "%s\n", __func__);
+ osmo_mslookup_client_request(client, &query, &handling);
+}
+
+static void client_stop(void)
+{
+ fprintf(stderr, "%s\n", __func__);
+ osmo_mslookup_client_free(client);
+ client = NULL;
+}
+const struct timeval fake_time_start_time = { 0, 0 };
+
+#define fake_time_passes(secs, usecs) do \
+{ \
+ struct timeval diff; \
+ osmo_gettimeofday_override_add(secs, usecs); \
+ osmo_clock_override_add(CLOCK_MONOTONIC, secs, usecs * 1000); \
+ timersub(&osmo_gettimeofday_override_time, &fake_time_start_time, &diff); \
+ LOGP(DMSLOOKUP, LOGL_DEBUG, "Total time passed: %d.%06d s\n", \
+ (int)diff.tv_sec, (int)diff.tv_usec); \
+ osmo_timers_prepare(); \
+ osmo_timers_update(); \
+} while (0)
+
+static void fake_time_start(void)
+{
+ struct timespec *clock_override;
+
+ osmo_gettimeofday_override_time = fake_time_start_time;
+ osmo_gettimeofday_override = true;
+ clock_override = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
+ OSMO_ASSERT(clock_override);
+ clock_override->tv_sec = fake_time_start_time.tv_sec;
+ clock_override->tv_nsec = fake_time_start_time.tv_usec * 1000;
+ osmo_clock_override_enable(CLOCK_MONOTONIC, true);
+ fake_time_passes(0, 0);
+}
+static void test_server_client(void)
+{
+ fprintf(stderr, "-- %s --\n", __func__);
+ server_init();
+ client_init();
+ client_query();
+
+ /* Let the server receive the query and indirectly call server_recv(). As side effect of using the same IP and
+ * port, the client will also receive its own question. The client will dismiss its own question, as it is just
+ * looking for answers. */
+ OSMO_ASSERT(osmo_select_main_ctx(1) == 1);
+
+ /* Let the mslookup client receive the answer (also same side effect as above). It does not call the callback
+ * (client_recv()) just yet, because it is waiting for the best result within two seconds. */
+ OSMO_ASSERT(osmo_select_main_ctx(1) == 1);
+
+ /* Time flies by, client_recv() gets called. */
+ fake_time_passes(5, 0);
+
+ server_stop();
+ client_stop();
+}
+
+bool is_multicast_enabled(void)
+{
+ bool ret = true;
+ struct addrinfo *ai;
+ int sock;
+ struct addrinfo hints = {0};
+ struct ip_mreq multicast_req = {0};
+ in_addr_t iface = INADDR_ANY;
+
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = (AI_PASSIVE | AI_NUMERICHOST);
+ assert(getaddrinfo("239.192.23.42", "4266", &hints, &ai) == 0);
+
+ sock = socket(ai->ai_family, ai->ai_socktype, 0);
+ assert(sock != -1);
+ assert(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, sizeof(iface)) != -1);
+
+ memcpy(&multicast_req.imr_multiaddr, &((struct sockaddr_in*)(ai->ai_addr))->sin_addr,
+ sizeof(multicast_req.imr_multiaddr));
+ multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicast_req, sizeof(multicast_req)) == -1)
+ ret = false;
+
+ freeaddrinfo(ai);
+ return ret;
+}
+
+/*
+ * Run all tests
+ */
+int main(int argc, char **argv)
+{
+ if (!is_multicast_enabled()) {
+ fprintf(stderr, "ERROR: multicast is disabled! (OS#4361)");
+ return 1;
+ }
+
+ talloc_enable_null_tracking();
+ ctx = talloc_named_const(NULL, 0, "main");
+ osmo_init_logging2(ctx, NULL);
+
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_print_level(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_category_filter(osmo_stderr_target, DMSLOOKUP, true, LOGL_DEBUG);
+
+ fake_time_start();
+
+ test_server_client();
+
+ log_fini();
+
+ OSMO_ASSERT(talloc_total_blocks(ctx) == 1);
+ talloc_free(ctx);
+ OSMO_ASSERT(talloc_total_blocks(NULL) == 1);
+ talloc_disable_null_tracking();
+
+ return 0;
+}
diff --git a/tests/mslookup/mslookup_client_mdns_test.err b/tests/mslookup/mslookup_client_mdns_test.err
new file mode 100644
index 0000000..b4ea269
--- /dev/null
+++ b/tests/mslookup/mslookup_client_mdns_test.err
@@ -0,0 +1,14 @@
+Total time passed: 0.000000 s
+-- test_server_client --
+server_init
+client_init
+client_query
+sending mDNS query: gsup.hlr.123456789012345.imsi
+server_recv
+received request
+server_recv
+client_recv
+client_recv(): gsup.hlr.123456789012345.imsi -> ipv4: 42.42.42.42:444 -> ipv6: [1122:3344:5566:7788:99aa:bbcc:ddee:ff00]:666 (age=3) (not-last)
+Total time passed: 5.000000 s
+server_stop
+client_stop
diff --git a/tests/mslookup/mslookup_client_test.c b/tests/mslookup/mslookup_client_test.c
new file mode 100644
index 0000000..84b7810
--- /dev/null
+++ b/tests/mslookup/mslookup_client_test.c
@@ -0,0 +1,245 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <string.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/select.h>
+#include <osmocom/hlr/logging.h>
+#include <osmocom/mslookup/mslookup_client_fake.h>
+#include <osmocom/mslookup/mslookup_client.h>
+
+#define SERVICE_HLR_GSUP "gsup.hlr"
+#define SERVICE_SIP "sip.voice"
+
+void *ctx = NULL;
+
+static struct osmo_mslookup_fake_response fake_lookup_responses[] = {
+ {
+ .time_to_reply = { .tv_sec = 1, },
+ .for_id = {
+ .type = OSMO_MSLOOKUP_ID_IMSI,
+ .imsi = "1234567",
+ },
+ .for_service = SERVICE_HLR_GSUP,
+ .result = {
+ .rc = OSMO_MSLOOKUP_RC_RESULT,
+ .host_v4 = {
+ .af = AF_INET,
+ .ip = "12.34.56.7",
+ .port = 42,
+ },
+ .host_v6 = {
+ .af = AF_INET6,
+ .ip = "be:ef:ed:ca:fe:fa:ce::1",
+ .port = 42,
+ },
+ .age = 0,
+ },
+ },
+ {
+ .time_to_reply = { .tv_usec = 600 * 1000, },
+ .for_id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "112",
+ },
+ .for_service = SERVICE_SIP,
+ .result = {
+ .rc = OSMO_MSLOOKUP_RC_RESULT,
+ .host_v4 = {
+ .af = AF_INET,
+ .ip = "66.66.66.66",
+ .port = 666,
+ },
+ .host_v6 = {
+ .af = AF_INET,
+ .ip = "6666:6666:6666::6",
+ .port = 666,
+ },
+ .age = 423,
+ },
+ },
+ {
+ .time_to_reply = { .tv_usec = 800 * 1000, },
+ .for_id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "112",
+ },
+ .for_service = SERVICE_SIP,
+ .result = {
+ .rc = OSMO_MSLOOKUP_RC_RESULT,
+ .host_v4 = {
+ .af = AF_INET,
+ .ip = "112.112.112.112",
+ .port = 23,
+ },
+ .age = 235,
+ },
+ },
+ {
+ .time_to_reply = { .tv_sec = 1, .tv_usec = 200 * 1000, },
+ .for_id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "112",
+ },
+ .for_service = SERVICE_SIP,
+ .result = {
+ .rc = OSMO_MSLOOKUP_RC_RESULT,
+ .host_v4 = {
+ .af = AF_INET,
+ .ip = "99.99.99.99",
+ .port = 999,
+ },
+ .host_v6 = {
+ .af = AF_INET,
+ .ip = "9999:9999:9999::9",
+ .port = 999,
+ },
+ .age = 335,
+ },
+ },
+ {
+ .time_to_reply = { .tv_sec = 1, .tv_usec = 500 * 1000, },
+ .for_id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "112",
+ },
+ .for_service = SERVICE_SIP,
+ .result = {
+ .rc = OSMO_MSLOOKUP_RC_RESULT,
+ .host_v4 = {
+ .af = AF_INET,
+ .ip = "99.99.99.99",
+ .port = 999,
+ },
+ .age = 999,
+ },
+ },
+};
+
+const struct timeval fake_time_start_time = { 0, 0 };
+
+#define fake_time_passes(secs, usecs) do \
+{ \
+ struct timeval diff; \
+ osmo_gettimeofday_override_add(secs, usecs); \
+ osmo_clock_override_add(CLOCK_MONOTONIC, secs, usecs * 1000); \
+ timersub(&osmo_gettimeofday_override_time, &fake_time_start_time, &diff); \
+ LOGP(DMSLOOKUP, LOGL_DEBUG, "Total time passed: %d.%06d s\n", \
+ (int)diff.tv_sec, (int)diff.tv_usec); \
+ osmo_timers_prepare(); \
+ osmo_timers_update(); \
+} while (0)
+
+static void fake_time_start(void)
+{
+ struct timespec *clock_override;
+
+ osmo_gettimeofday_override_time = fake_time_start_time;
+ osmo_gettimeofday_override = true;
+ clock_override = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
+ OSMO_ASSERT(clock_override);
+ clock_override->tv_sec = fake_time_start_time.tv_sec;
+ clock_override->tv_nsec = fake_time_start_time.tv_usec * 1000;
+ osmo_clock_override_enable(CLOCK_MONOTONIC, true);
+ fake_time_passes(0, 0);
+}
+
+static void result_cb_once(struct osmo_mslookup_client *client,
+ uint32_t request_handle,
+ const struct osmo_mslookup_query *query,
+ const struct osmo_mslookup_result *result)
+{
+ LOGP(DMSLOOKUP, LOGL_DEBUG, "result_cb(): %s\n", osmo_mslookup_result_name_c(ctx, query, result));
+}
+
+int main(int argc, char **argv)
+{
+ ctx = talloc_named_const(NULL, 0, "main");
+ osmo_init_logging2(ctx, NULL);
+
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_print_level(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_category_filter(osmo_stderr_target, DMSLOOKUP, true, LOGL_DEBUG);
+
+ fake_time_start();
+
+ struct osmo_mslookup_client *client = osmo_mslookup_client_new(ctx);
+ osmo_mslookup_client_add_fake(client, fake_lookup_responses, ARRAY_SIZE(fake_lookup_responses));
+
+ /* Place some requests to be replied upon asynchronously */
+
+ struct osmo_mslookup_query_handling handling = {
+ .result_timeout_milliseconds = 1, /* set some timeout < min_wait_milliseconds */
+ .min_wait_milliseconds = 2000,
+ .result_cb = result_cb_once,
+ };
+
+ struct osmo_mslookup_query q1 = {
+ .service = SERVICE_HLR_GSUP,
+ .id = {
+ .type = OSMO_MSLOOKUP_ID_IMSI,
+ .imsi = "1234567",
+ },
+ };
+ OSMO_ASSERT(osmo_mslookup_client_request(client, &q1, &handling));
+
+ struct osmo_mslookup_query q2 = {
+ .service = SERVICE_SIP,
+ .id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "112",
+ },
+ };
+ handling.min_wait_milliseconds = 3000;
+ OSMO_ASSERT(osmo_mslookup_client_request(client, &q2, &handling));
+
+ struct osmo_mslookup_query q3 = {
+ .service = "smpp.sms",
+ .id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "00000",
+ },
+ };
+ handling.min_wait_milliseconds = 5000;
+ OSMO_ASSERT(osmo_mslookup_client_request(client, &q3, &handling));
+
+ struct osmo_mslookup_query q4 = {
+ .service = SERVICE_HLR_GSUP,
+ .id = {
+ .type = OSMO_MSLOOKUP_ID_MSISDN,
+ .msisdn = "666",
+ },
+ };
+ handling.min_wait_milliseconds = 10000;
+ uint32_t q4_handle;
+ OSMO_ASSERT((q4_handle = osmo_mslookup_client_request(client, &q4, &handling)));
+
+ while (osmo_gettimeofday_override_time.tv_sec < 6) {
+ log_reset_context();
+ fake_time_passes(0, 1e6 / 5);
+ }
+
+ osmo_mslookup_client_request_cancel(client, q4_handle);
+
+ return 0;
+}
diff --git a/tests/mslookup/mslookup_client_test.err b/tests/mslookup/mslookup_client_test.err
new file mode 100644
index 0000000..c552837
--- /dev/null
+++ b/tests/mslookup/mslookup_client_test.err
@@ -0,0 +1,47 @@
+Total time passed: 0.000000 s
+fake_lookup_request(gsup.hlr.1234567.imsi)
+fake_lookup_request(sip.voice.112.msisdn)
+fake_lookup_request(smpp.sms.00000.msisdn)
+fake_lookup_request(gsup.hlr.666.msisdn)
+Total time passed: 0.200000 s
+Total time passed: 0.400000 s
+Total time passed: 0.600000 s
+osmo_mslookup_client_rx_result(): sip.voice.112.msisdn -> ipv4: 66.66.66.66:666 -> ipv6: 6666:6666:6666::6:666 (age=423) (not-last)
+Total time passed: 0.800000 s
+osmo_mslookup_client_rx_result(): sip.voice.112.msisdn -> ipv4: 112.112.112.112:23 (age=235) (not-last)
+Total time passed: 1.000000 s
+osmo_mslookup_client_rx_result(): gsup.hlr.1234567.imsi -> ipv4: 12.34.56.7:42 -> ipv6: [be:ef:ed:ca:fe:fa:ce::1]:42 (age=0) (not-last)
+result_cb(): gsup.hlr.1234567.imsi -> ipv4: 12.34.56.7:42 -> ipv6: [be:ef:ed:ca:fe:fa:ce::1]:42 (age=0) (last)
+fake_lookup_request_cleanup() ok
+Total time passed: 1.200000 s
+osmo_mslookup_client_rx_result(): sip.voice.112.msisdn -> ipv4: 99.99.99.99:999 -> ipv6: 9999:9999:9999::9:999 (age=335) (not-last)
+Total time passed: 1.400000 s
+Total time passed: 1.600000 s
+osmo_mslookup_client_rx_result(): sip.voice.112.msisdn -> ipv4: 99.99.99.99:999 (age=999) (not-last)
+Total time passed: 1.800000 s
+Total time passed: 2.000000 s
+Total time passed: 2.200000 s
+Total time passed: 2.400000 s
+Total time passed: 2.600000 s
+Total time passed: 2.800000 s
+Total time passed: 3.000000 s
+result_cb(): sip.voice.112.msisdn -> ipv4: 112.112.112.112:23 (age=235) (last)
+fake_lookup_request_cleanup() ok
+Total time passed: 3.200000 s
+Total time passed: 3.400000 s
+Total time passed: 3.600000 s
+Total time passed: 3.800000 s
+Total time passed: 4.000000 s
+Total time passed: 4.200000 s
+Total time passed: 4.400000 s
+Total time passed: 4.600000 s
+Total time passed: 4.800000 s
+Total time passed: 5.000000 s
+result_cb(): smpp.sms.00000.msisdn not-found (last)
+fake_lookup_request_cleanup() ok
+Total time passed: 5.200000 s
+Total time passed: 5.400000 s
+Total time passed: 5.600000 s
+Total time passed: 5.800000 s
+Total time passed: 6.000000 s
+fake_lookup_request_cleanup() ok
diff --git a/tests/mslookup/mslookup_test.c b/tests/mslookup/mslookup_test.c
new file mode 100644
index 0000000..742e14b
--- /dev/null
+++ b/tests/mslookup/mslookup_test.c
@@ -0,0 +1,88 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/select.h>
+#include <osmocom/hlr/logging.h>
+#include <osmocom/mslookup/mslookup_client.h>
+
+void *ctx;
+
+const char *domains[] = {
+ "gsup.hlr.123456789012345.imsi",
+ "gsup.hlr.1.imsi",
+ "sip.voice.1.msisdn",
+ "a.b.c.imsi",
+ "",
+ ".",
+ "...",
+ ".....",
+ ".....1.msisdn",
+ "fofdndsf. d.ads ofdsf. ads.kj.1243455132.msisdn",
+ "foo.12345678901234567890.imsi",
+ "gsup.hlr.123456789012345.what",
+ NULL,
+ "blarg",
+ "blarg.",
+ "blarg.1.",
+ "blarg.1.msisdn",
+ "blarg.1.msisdn.",
+ ".1.msisdn",
+ "1.msisdn",
+ "qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmm.1.msisdn",
+ "qwerty.1.qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmm",
+};
+
+void test_osmo_mslookup_query_init_from_domain_str(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(domains); i++) {
+ const char *d = domains[i];
+ struct osmo_mslookup_query q;
+
+ int rc = osmo_mslookup_query_init_from_domain_str(&q, d);
+ if (rc)
+ fprintf(stderr, "%s -> rc = %d\n", osmo_quote_str(d, -1), rc);
+ else
+ fprintf(stderr, "%s -> %s %s %s\n", osmo_quote_str(d, -1),
+ osmo_quote_str_c(ctx, q.service, -1),
+ osmo_quote_str_c(ctx, q.id.imsi, -1),
+ osmo_mslookup_id_type_name(q.id.type));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ ctx = talloc_named_const(NULL, 0, "main");
+ osmo_init_logging2(ctx, NULL);
+
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_print_level(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_category_filter(osmo_stderr_target, DMSLOOKUP, true, LOGL_DEBUG);
+
+ test_osmo_mslookup_query_init_from_domain_str();
+
+ talloc_free(ctx);
+
+ return 0;
+}
diff --git a/tests/mslookup/mslookup_test.err b/tests/mslookup/mslookup_test.err
new file mode 100644
index 0000000..ee5ff21
--- /dev/null
+++ b/tests/mslookup/mslookup_test.err
@@ -0,0 +1,22 @@
+"gsup.hlr.123456789012345.imsi" -> "gsup.hlr" "123456789012345" imsi
+"gsup.hlr.1.imsi" -> rc = -5
+"sip.voice.1.msisdn" -> "sip.voice" "1" msisdn
+"a.b.c.imsi" -> rc = -5
+"" -> rc = -2
+"." -> rc = -3
+"..." -> rc = -4
+"....." -> rc = -4
+".....1.msisdn" -> "...." "1" msisdn
+"fofdndsf. d.ads ofdsf. ads.kj.1243455132.msisdn" -> "fofdndsf. d.ads ofdsf. ads.kj" "1243455132" msisdn
+"foo.12345678901234567890.imsi" -> rc = -11
+"gsup.hlr.123456789012345.what" -> rc = -7
+NULL -> rc = -1
+"blarg" -> rc = -2
+"blarg." -> rc = -3
+"blarg.1." -> rc = -4
+"blarg.1.msisdn" -> "blarg" "1" msisdn
+"blarg.1.msisdn." -> rc = -4
+".1.msisdn" -> rc = -3
+"1.msisdn" -> rc = -3
+"qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmm.1.msisdn" -> rc = -11
+"qwerty.1.qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmm" -> rc = -7
diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty
index bf2afaf..4aea638 100644
--- a/tests/test_nodes.vty
+++ b/tests/test_nodes.vty
@@ -1,106 +1,90 @@
+OsmoHLR> ?
+ show Show running system information
+ list Print command list
+ exit Exit current mode and down to previous mode
+ help Description of the interactive help system
+ enable Turn on privileged mode command
+ terminal Set terminal line parameters
+ who Display who is on vty
+ logging Configure logging
+ no Negate a command or set its defaults
+ logp Print a message on all log outputs; useful for placing markers in test logs
+ subscriber Subscriber management commands
OsmoHLR> list
- show version
- show online-help
- list
- exit
- help
- enable
- terminal length <0-512>
- terminal no length
- who
- show history
- logging enable
-...
- show logging vty
- show alarms
- show talloc-context (application|all) (full|brief|DEPTH)
- show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS
- show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP
- show stats
- show stats level (global|peer|subscriber)
- show asciidoc counters
- show rate-counters
+...
show gsup-connections
+ show subscribers all
+ show subscribers (imei|imsi|msisdn) FILTER
+ show subscribers (cs|ps) (on|off)
+ show subscribers last-seen
subscriber (imsi|msisdn|id|imei) IDENT show
show subscriber (imsi|msisdn|id|imei) IDENT
+ show mslookup services
+...
OsmoHLR> enable
-OsmoHLR# list
- help
- list
- write terminal
- write file
- write memory
- write
- show running-config
- exit
- disable
- configure terminal
- copy running-config startup-config
- show startup-config
- show version
- show online-help
- terminal length <0-512>
- terminal no length
- who
- show history
- terminal monitor
- terminal no monitor
- logging enable
+OsmoHLR# ?
...
+ subscriber Subscriber management commands
OsmoHLR# configure terminal
+OsmoHLR(config)# ?
+...
+ hlr Configure the HLR
+ mslookup Configure Distributed GSM mslookup
+...
+
OsmoHLR(config)# list
- help
- list
- write terminal
- write file
- write memory
- write
- show running-config
- exit
- end
...
hlr
+ mslookup
+...
OsmoHLR(config)# hlr
+OsmoHLR(config-hlr)# ?
+...
+ euse Configure a particular External USSD Entity
+ no Negate a command or set its defaults
+ ussd USSD Configuration
+ ncss-guard-timeout Set guard timer for NCSS (call independent SS) session activity
+ smsc Configuration of GSUP routing to SMSCs
+ reject-cause GSUP/GMM cause to be sent
+ store-imei Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').
+ subscriber-create-on-demand Make a new record when a subscriber is first seen.
OsmoHLR(config-hlr)# list
- help
- list
- write terminal
- write file
- write memory
- write
- show running-config
- exit
- end
+...
gsup
+ ps
database PATH
euse NAME
no euse NAME
- ussd route prefix PREFIX internal (own-msisdn|own-imsi)
+ ussd route prefix PREFIX internal (own-msisdn|own-imsi|test-idle)
ussd route prefix PREFIX external EUSE
no ussd route prefix PREFIX
ussd default-route external EUSE
no ussd default-route
ncss-guard-timeout <0-255>
+ smsc entity NAME
+ no smsc entity NAME
+ smsc route NUMBER NAME
+ no smsc route NUMBER
+ smsc default-route NAME
+ no smsc default-route
+ reject-cause (not-found|no-proxy) (imsi-unknown|illegal-ms|plmn-not-allowed|la-not-allowed|roaming-not-allowed|no-suitable-cell-in-la|net-fail|congestion|auth-unacceptable|proto-error-unspec)
store-imei
no store-imei
subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)
no subscriber-create-on-demand
OsmoHLR(config-hlr)# gsup
+OsmoHLR(config-hlr-gsup)# ?
+...
+ bind Listen/Bind related socket option
+ ipa-name Set the IPA name of this HLR, for proxying to remote HLRs
OsmoHLR(config-hlr-gsup)# list
- help
- list
- write terminal
- write file
- write memory
- write
- show running-config
- exit
- end
+...
bind ip A.B.C.D
+ ipa-name NAME
OsmoHLR(config-hlr-gsup)# exit
OsmoHLR(config-hlr)# exit
@@ -123,13 +107,399 @@ log stderr
logging level main notice
logging level db notice
logging level auc notice
- logging level ss info
+ logging level ss notice
+ logging level mslookup notice
+ logging level lu notice
+ logging level dgsm notice
...
hlr
store-imei
database hlr_vty_test.db
gsup
bind ip 127.0.0.1
+ ipa-name unnamed-HLR
ussd route prefix *#100# internal own-msisdn
ussd route prefix *#101# internal own-imsi
+ ps
+ pdp-profiles default
+ profile 1
+ apn internet
+ profile 2
+ apn *
end
+
+OsmoHLR# configure terminal
+
+OsmoHLR(config)# mslookup
+OsmoHLR(config-mslookup)# ?
+...
+ mdns Multicast DNS related configuration
+ no Negate a command or set its defaults
+ server Enable and configure Distributed GSM mslookup server
+ client Enable and configure Distributed GSM mslookup client
+OsmoHLR(config-mslookup)# list
+...
+ mdns bind [IP] [<1-65535>]
+ mdns domain-suffix DOMAIN_SUFFIX
+ no mdns bind
+ server
+ no server
+ client
+ no client
+
+OsmoHLR(config-mslookup)# ?
+...
+ mdns Multicast DNS related configuration
+ no Negate a command or set its defaults
+ server Enable and configure Distributed GSM mslookup server
+ client Enable and configure Distributed GSM mslookup client
+OsmoHLR(config-mslookup)# no?
+ no Negate a command or set its defaults
+OsmoHLR(config-mslookup)# no ?
+ mdns Disable both server and client for mDNS mslookup
+ server Disable Distributed GSM mslookup server
+ client Disable Distributed GSM mslookup client
+OsmoHLR(config-mslookup)# mdns ?
+ bind Convenience shortcut: enable and configure both server and client for mDNS mslookup
+ domain-suffix mDNS domain suffix (default: mdns.osmocom.org). This is appended and stripped from mDNS packets during encoding/decoding, so we don't collide with top-level domains administrated by IANA
+OsmoHLR(config-mslookup)# mdns bind ?
+ [IP] multicast IPv4 address like 239.192.23.42 or IPv6 address like ff08::23:42
+OsmoHLR(config-mslookup)# mdns bind 1.2.3.4 ?
+ [<1-65535>] mDNS UDP Port number
+OsmoHLR(config-mslookup)# mdns domain-suffix ?
+ DOMAIN_SUFFIX mDNS domain suffix (default: mdns.osmocom.org). This is appended and stripped from mDNS packets during encoding/decoding, so we don't collide with top-level domains administrated by IANA
+
+OsmoHLR(config-mslookup)# server
+OsmoHLR(config-mslookup-server)# ?
+...
+ mdns Multicast DNS related configuration
+ no Negate a command or set its defaults
+ service Configure addresses of local services, as sent in replies to remote mslookup requests.
+ msc Configure services for individual local MSCs
+OsmoHLR(config-mslookup-server)# list
+...
+ mdns bind [IP] [<1-65535>]
+ mdns domain-suffix DOMAIN_SUFFIX
+ no mdns bind
+ service NAME at IP <1-65535>
+ no service NAME
+ no service NAME at IP <1-65535>
+ msc ipa-name .IPA_NAME
+
+OsmoHLR(config-mslookup-server)# mdns ?
+ bind Configure where the mDNS server listens for mslookup requests
+ domain-suffix mDNS domain suffix (default: mdns.osmocom.org). This is appended and stripped from mDNS packets during encoding/decoding, so we don't collide with top-level domains administrated by IANA
+OsmoHLR(config-mslookup-server)# mdns bind ?
+ [IP] multicast IPv4 address like 239.192.23.42 or IPv6 address like ff08::23:42
+OsmoHLR(config-mslookup-server)# mdns bind 1.2.3.4 ?
+ [<1-65535>] mDNS UDP Port number
+
+OsmoHLR(config-mslookup-server)# service?
+ service Configure addresses of local services, as sent in replies to remote mslookup requests.
+OsmoHLR(config-mslookup-server)# service ?
+ NAME mslookup service name, e.g. sip.voice or smpp.sms
+OsmoHLR(config-mslookup-server)# service foo ?
+ at at
+OsmoHLR(config-mslookup-server)# service foo at ?
+ IP IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1
+OsmoHLR(config-mslookup-server)# service foo at 1.2.3.4 ?
+ <1-65535> Service-specific port number
+
+OsmoHLR(config-mslookup-server)# no ?
+ mdns Disable server for mDNS mslookup (do not answer remote requests)
+ service Remove one or more service address entries
+OsmoHLR(config-mslookup-server)# no service ?
+ NAME mslookup service name, e.g. sip.voice or smpp.sms
+OsmoHLR(config-mslookup-server)# no service foo ?
+ at at
+ <cr>
+OsmoHLR(config-mslookup-server)# no service foo at ?
+ IP IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1
+OsmoHLR(config-mslookup-server)# no service foo at 1.2.3.4 ?
+ <1-65535> Service-specific port number
+
+OsmoHLR(config-mslookup-server)# msc?
+ msc Configure services for individual local MSCs
+OsmoHLR(config-mslookup-server)# msc ?
+ ipa-name Identify locally connected MSC by IPA Unit Name
+OsmoHLR(config-mslookup-server)# msc ipa-name ?
+ IPA_NAME IPA Unit Name of the local MSC to configure
+
+OsmoHLR(config-mslookup-server)# msc ipa-name MSC-1
+OsmoHLR(config-mslookup-server-msc)# ?
+...
+ service Configure addresses of local services, as sent in replies to remote mslookup requests.
+ no Negate a command or set its defaults
+OsmoHLR(config-mslookup-server-msc)# list
+...
+ service NAME at IP <1-65535>
+ no service NAME
+ no service NAME at IP <1-65535>
+
+OsmoHLR(config-mslookup-server-msc)# service?
+ service Configure addresses of local services, as sent in replies to remote mslookup requests.
+OsmoHLR(config-mslookup-server-msc)# service ?
+ NAME mslookup service name, e.g. sip.voice or smpp.sms
+OsmoHLR(config-mslookup-server-msc)# service foo ?
+ at at
+OsmoHLR(config-mslookup-server-msc)# service foo at ?
+ IP IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1
+OsmoHLR(config-mslookup-server-msc)# service foo at 1.2.3.4 ?
+ <1-65535> Service-specific port number
+
+OsmoHLR(config-mslookup-server-msc)# no ?
+ service Remove one or more service address entries
+OsmoHLR(config-mslookup-server-msc)# no service ?
+ NAME mslookup service name, e.g. sip.voice or smpp.sms
+OsmoHLR(config-mslookup-server-msc)# no service foo ?
+ at at
+ <cr>
+OsmoHLR(config-mslookup-server-msc)# no service foo at ?
+ IP IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1
+OsmoHLR(config-mslookup-server-msc)# no service foo at 1.2.3.4 ?
+ <1-65535> Service-specific port number
+
+OsmoHLR(config-mslookup-server-msc)# exit
+OsmoHLR(config-mslookup-server)# exit
+OsmoHLR(config-mslookup)# client
+OsmoHLR(config-mslookup-client)# ?
+...
+ timeout How long should the mslookup client wait for remote responses before evaluating received results
+ mdns Multicast DNS related configuration
+ no Negate a command or set its defaults
+ gateway-proxy Configure a fixed IP address to send all GSUP requests for unknown IMSIs to, without invoking a lookup for IMSI
+OsmoHLR(config-mslookup-client)# list
+...
+ timeout <1-100000>
+ mdns bind [IP] [<1-65535>]
+ mdns domain-suffix DOMAIN_SUFFIX
+ no mdns bind
+ gateway-proxy IP [<1-65535>]
+ no gateway-proxy
+
+OsmoHLR(config-mslookup-client)# timeout?
+ timeout How long should the mslookup client wait for remote responses before evaluating received results
+OsmoHLR(config-mslookup-client)# timeout ?
+ <1-100000> timeout in milliseconds
+
+OsmoHLR(config-mslookup-client)# mdns?
+ mdns Multicast DNS related configuration
+OsmoHLR(config-mslookup-client)# mdns bind?
+ bind Enable mDNS client, and configure multicast address to send mDNS mslookup requests to
+OsmoHLR(config-mslookup-client)# mdns bind ?
+ [IP] multicast IPv4 address like 239.192.23.42 or IPv6 address like ff08::23:42
+OsmoHLR(config-mslookup-client)# mdns bind 1.2.3.4 ?
+ [<1-65535>] mDNS UDP Port number
+OsmoHLR(config-mslookup-client)# mdns domain-suffix?
+ domain-suffix mDNS domain suffix (default: mdns.osmocom.org). This is appended and stripped from mDNS packets during encoding/decoding, so we don't collide with top-level domains administrated by IANA
+OsmoHLR(config-mslookup-client)# mdns domain-suffix ?
+ DOMAIN_SUFFIX mDNS domain suffix (default: mdns.osmocom.org). This is appended and stripped from mDNS packets during encoding/decoding, so we don't collide with top-level domains administrated by IANA
+
+
+OsmoHLR(config-mslookup-client)# gateway-proxy?
+ gateway-proxy Configure a fixed IP address to send all GSUP requests for unknown IMSIs to, without invoking a lookup for IMSI
+OsmoHLR(config-mslookup-client)# gateway-proxy ?
+ IP IP address of the remote HLR
+OsmoHLR(config-mslookup-client)# gateway-proxy 1.2.3.4 ?
+ [<1-65535>] GSUP port number (omit for default 4222)
+
+OsmoHLR(config-mslookup-client)# no?
+ no Negate a command or set its defaults
+OsmoHLR(config-mslookup-client)# no ?
+ mdns Disable mDNS client, do not query remote services by mDNS
+ gateway-proxy Disable gateway proxy for GSUP with unknown IMSIs
+
+OsmoHLR(config-mslookup-client)# gateway-proxy ?
+ IP IP address of the remote HLR
+OsmoHLR(config-mslookup-client)# gateway-proxy 1.2.3.4 ?
+ [<1-65535>] GSUP port number (omit for default 4222)
+
+OsmoHLR(config-mslookup-client)# do show mslookup?
+ mslookup Distributed GSM / mslookup related information
+OsmoHLR(config-mslookup-client)# do show mslookup ?
+ services List configured service addresses as sent to remote mslookup requests
+
+OsmoHLR(config-mslookup-client)# gateway-proxy 1.2.3.4
+
+OsmoHLR(config-mslookup-client)# exit
+
+OsmoHLR(config-mslookup)# mdns bind
+OsmoHLR(config-mslookup)# server
+OsmoHLR(config-mslookup-server)# service qwert at 123.45.67.89 qwert
+% Unknown command.
+OsmoHLR(config-mslookup-server)# service qwert at qwert 1234
+% mslookup server: Invalid address for service qwert: qwert 1234
+OsmoHLR(config-mslookup-server)# service foo.bar at 123.45.67.89 1011
+OsmoHLR(config-mslookup-server)# service baz.bar at 121.31.41.5 1617
+OsmoHLR(config-mslookup-server)# service baz.bar at a:b:c::d 1819
+OsmoHLR(config-mslookup-server)# msc ipa-name msc-901-70-23
+OsmoHLR(config-mslookup-server-msc)# service foo.bar at 76.54.32.10 1234
+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 12.11.10.98 7654
+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 999:999:999::999 9999
+OsmoHLR(config-mslookup-server-msc)# service baz.bar at dd:cc:bb::a 3210
+OsmoHLR(config-mslookup-server-msc)# exit
+OsmoHLR(config-mslookup-server)# msc ipa-name msc-901-70-42
+OsmoHLR(config-mslookup-server-msc)# service foo.bar at 1.1.1.1 1111
+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 2.2.2.2 2222
+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 2222:2222:2222::2 2222
+OsmoHLR(config-mslookup-server-msc)# do show mslookup services
+Local GSUP HLR address returned in mslookup responses for local IMSIs: 127.0.0.1:4222
+service foo.bar at 123.45.67.89 1011
+service baz.bar at 121.31.41.5 1617
+service baz.bar at a:b:c::d 1819
+msc ipa-name MSC-1
+msc ipa-name msc-901-70-23
+ service foo.bar at 76.54.32.10 1234
+ service baz.bar at 12.11.10.98 7654
+ service baz.bar at dd:cc:bb::a 3210
+msc ipa-name msc-901-70-42
+ service foo.bar at 1.1.1.1 1111
+ service baz.bar at 2.2.2.2 2222
+ service baz.bar at 2222:2222:2222::2 2222
+
+OsmoHLR(config-mslookup-server-msc)# show running-config
+...
+mslookup
+ server
+ mdns bind 239.192.23.42 4266
+ service foo.bar at 123.45.67.89 1011
+ service baz.bar at 121.31.41.5 1617
+ service baz.bar at a:b:c::d 1819
+ msc ipa-name MSC-1
+ msc ipa-name msc-901-70-23
+ service foo.bar at 76.54.32.10 1234
+ service baz.bar at 12.11.10.98 7654
+ service baz.bar at dd:cc:bb::a 3210
+ msc ipa-name msc-901-70-42
+ service foo.bar at 1.1.1.1 1111
+ service baz.bar at 2.2.2.2 2222
+ service baz.bar at 2222:2222:2222::2 2222
+ client
+ gateway-proxy 1.2.3.4 4222
+ mdns bind 239.192.23.42 4266
+...
+
+OsmoHLR(config-mslookup-server-msc)# no service baz.bar
+OsmoHLR(config-mslookup-server-msc)# no service asdf
+% mslookup server: cannot remove service 'asdf'
+OsmoHLR(config-mslookup-server-msc)# exit
+OsmoHLR(config-mslookup-server)# msc ipa-name msc-901-70-23
+OsmoHLR(config-mslookup-server-msc)# no service baz.bar at dd:cc:bb::a 3210
+% mslookup server: cannot remove service 'baz.bar' to dd:cc:bb::a 3210
+OsmoHLR(config-mslookup-server-msc)# no service asdf at asdf asdf
+% Unknown command.
+OsmoHLR(config-mslookup-server-msc)# no service asdf at asdf 3210
+% mslookup server: Invalid address for 'no service' asdf: asdf 3210
+OsmoHLR(config-mslookup-server-msc)# no service asdf at dd:cc:bb::a 3210
+% mslookup server: cannot remove service 'asdf' to dd:cc:bb::a 3210
+OsmoHLR(config-mslookup-server-msc)# exit
+OsmoHLR(config-mslookup-server)# no service baz.bar at 2.2.2.2 2222
+% mslookup server: cannot remove service 'baz.bar' to 2.2.2.2 2222
+OsmoHLR(config-mslookup-server)# no service baz.bar at a:b:c::d 1819
+% mslookup server: cannot remove service 'baz.bar' to a:b:c::d 1819
+
+OsmoHLR(config-mslookup-server)# exit
+OsmoHLR(config-mslookup)# client
+OsmoHLR(config-mslookup-client)# no gateway-proxy
+
+OsmoHLR(config-mslookup-client)# do show mslookup services
+Local GSUP HLR address returned in mslookup responses for local IMSIs: 127.0.0.1:4222
+service foo.bar at 123.45.67.89 1011
+service baz.bar at 121.31.41.5 1617
+msc ipa-name MSC-1
+msc ipa-name msc-901-70-23
+ service foo.bar at 76.54.32.10 1234
+ service baz.bar at 12.11.10.98 7654
+msc ipa-name msc-901-70-42
+ service foo.bar at 1.1.1.1 1111
+
+OsmoHLR(config-mslookup-client)# show running-config
+...
+mslookup
+ server
+ mdns bind 239.192.23.42 4266
+ service foo.bar at 123.45.67.89 1011
+ service baz.bar at 121.31.41.5 1617
+ msc ipa-name MSC-1
+ msc ipa-name msc-901-70-23
+ service foo.bar at 76.54.32.10 1234
+ service baz.bar at 12.11.10.98 7654
+ msc ipa-name msc-901-70-42
+ service foo.bar at 1.1.1.1 1111
+ client
+ mdns bind 239.192.23.42 4266
+...
+
+OsmoHLR(config-mslookup-client)# exit
+OsmoHLR(config-mslookup)# server
+OsmoHLR(config-mslookup-server)# service gsup.hlr at 23.42.17.11 4223
+OsmoHLR(config-mslookup-server)# do show mslookup services
+Local GSUP HLR address returned in mslookup responses for local IMSIs: 23.42.17.11:4223
+service foo.bar at 123.45.67.89 1011
+service baz.bar at 121.31.41.5 1617
+service gsup.hlr at 23.42.17.11 4223
+msc ipa-name MSC-1
+msc ipa-name msc-901-70-23
+ service foo.bar at 76.54.32.10 1234
+ service baz.bar at 12.11.10.98 7654
+msc ipa-name msc-901-70-42
+ service foo.bar at 1.1.1.1 1111
+
+OsmoHLR(config-mslookup-server)# show running-config
+...
+mslookup
+ server
+ mdns bind 239.192.23.42 4266
+ service foo.bar at 123.45.67.89 1011
+ service baz.bar at 121.31.41.5 1617
+ service gsup.hlr at 23.42.17.11 4223
+ msc ipa-name MSC-1
+ msc ipa-name msc-901-70-23
+ service foo.bar at 76.54.32.10 1234
+ service baz.bar at 12.11.10.98 7654
+ msc ipa-name msc-901-70-42
+ service foo.bar at 1.1.1.1 1111
+ client
+ mdns bind 239.192.23.42 4266
+...
+OsmoHLR(config-mslookup-server)# end
+OsmoHLR# configure terminal
+
+OsmoHLR(config)# hlr
+OsmoHLR(config-hlr)# ps?
+ ps Configure the PS options
+
+OsmoHLR(config-hlr)# ps
+
+OsmoHLR(config-hlr-ps)# list
+...
+ pdp-profiles default
+ no pdp-profiles default
+...
+OsmoHLR(config-hlr-ps)# no pdp-profiles default
+
+
+OsmoHLR(config-hlr-ps)# pdp-profiles default
+OsmoHLR(config-hlr-ps-pdp-profiles)# ?
+...
+ profile Configure a PDP profile
+...
+OsmoHLR(config-hlr-ps-pdp-profiles)# profile 1
+
+OsmoHLR(config-hlr-ps-pdp-profile)# ?
+...
+ apn Configure the APN.
+...
+OsmoHLR(config-hlr-ps-pdp-profile)# apn internet
+OsmoHLR(config-hlr-ps-pdp-profile)# exit
+OsmoHLR(config-hlr-ps-pdp-profiles)# profile 2
+OsmoHLR(config-hlr-ps-pdp-profile)# apn *
+OsmoHLR(config-hlr-ps-pdp-profile)# show running-config
+...
+ ps
+ pdp-profiles default
+ profile 1
+ apn internet
+ profile 2
+ apn *
+...
diff --git a/tests/test_subscriber.ctrl b/tests/test_subscriber.ctrl
index 4cefa4d..c2f09dc 100644
--- a/tests/test_subscriber.ctrl
+++ b/tests/test_subscriber.ctrl
@@ -610,5 +610,102 @@ periodic_lu_timer 0
periodic_rau_tau_timer 0
lmsi 00000000
-GET 101 subscriber.by-id-0x0123.info
-ERROR 101 Invalid value part of 'by-xxx-value' selector.
+SET 101 subscriber.create 901991234567891
+SET_REPLY 101 subscriber.create 124
+
+GET 102 subscriber.by-id-124.info
+GET_REPLY 102 subscriber.by-id-124.info
+id 124
+imsi 901991234567891
+nam_cs 1
+nam_ps 1
+ms_purged_cs 0
+ms_purged_ps 0
+periodic_lu_timer 0
+periodic_rau_tau_timer 0
+lmsi 00000000
+
+GET 103 subscriber.by-imsi-901991234567891.msisdn
+GET_REPLY 103 subscriber.by-imsi-901991234567891.msisdn none
+
+SET 104 subscriber.by-imsi-901991234567891.msisdn 555666
+SET_REPLY 104 subscriber.by-imsi-901991234567891.msisdn OK
+
+GET 105 subscriber.by-imsi-901991234567891.msisdn
+GET_REPLY 105 subscriber.by-imsi-901991234567891.msisdn 555666
+
+SET 106 subscriber.by-imsi-901991234567891.msisdn 888000
+SET_REPLY 106 subscriber.by-imsi-901991234567891.msisdn OK
+
+GET 107 subscriber.by-imsi-901991234567891.msisdn
+GET_REPLY 107 subscriber.by-imsi-901991234567891.msisdn 888000
+
+GET 108 subscriber.by-imsi-901991234567891.info
+GET_REPLY 108 subscriber.by-imsi-901991234567891.info
+id 124
+imsi 901991234567891
+msisdn 888000
+nam_cs 1
+nam_ps 1
+ms_purged_cs 0
+ms_purged_ps 0
+periodic_lu_timer 0
+periodic_rau_tau_timer 0
+lmsi 00000000
+
+SET 109 subscriber.by-imsi-901991234567891.msisdn none
+SET_REPLY 109 subscriber.by-imsi-901991234567891.msisdn OK
+
+GET 110 subscriber.by-imsi-901991234567891.msisdn
+GET_REPLY 110 subscriber.by-imsi-901991234567891.msisdn none
+
+GET 111 subscriber.by-imsi-901991234567891.info
+GET_REPLY 111 subscriber.by-imsi-901991234567891.info
+id 124
+imsi 901991234567891
+nam_cs 1
+nam_ps 1
+ms_purged_cs 0
+ms_purged_ps 0
+periodic_lu_timer 0
+periodic_rau_tau_timer 0
+lmsi 00000000
+
+GET 112 subscriber.by-imsi-901991234567891.aud2g
+GET_REPLY 112 subscriber.by-imsi-901991234567891.aud2g none
+
+SET 113 subscriber.by-imsi-901991234567891.aud2g xor-2g,c01ffedc1cadaeac1d1f1edacac1ab0a
+SET_REPLY 113 subscriber.by-imsi-901991234567891.aud2g OK
+
+GET 114 subscriber.by-imsi-901991234567891.aud2g
+GET_REPLY 114 subscriber.by-imsi-901991234567891.aud2g XOR-2G,c01ffedc1cadaeac1d1f1edacac1ab0a
+
+SET 115 subscriber.by-imsi-901991234567891.aud2g none
+SET_REPLY 115 subscriber.by-imsi-901991234567891.aud2g OK
+
+GET 116 subscriber.by-imsi-901991234567891.aud2g
+GET_REPLY 116 subscriber.by-imsi-901991234567891.aud2g none
+
+GET 117 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 117 subscriber.by-imsi-901991234567891.aud3g none
+
+SET 118 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,FB2A3D1B360F599ABAB99DB8669F8308
+SET_REPLY 118 subscriber.by-imsi-901991234567891.aud3g OK
+
+GET 119 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 119 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,fb2a3d1b360f599abab99db8669f8308,5
+
+SET 120 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,FB2A3D1B360F599ABAB99DB8669F8308,7
+SET_REPLY 120 subscriber.by-imsi-901991234567891.aud3g OK
+
+GET 121 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 121 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,7
+
+SET 122 subscriber.by-imsi-901991234567891.aud3g none
+SET_REPLY 122 subscriber.by-imsi-901991234567891.aud3g OK
+
+GET 123 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 123 subscriber.by-imsi-901991234567891.aud3g none
+
+SET 124 subscriber.delete 901991234567891
+SET_REPLY 124 subscriber.delete 124
diff --git a/tests/test_subscriber.vty b/tests/test_subscriber.vty
index 8e9026d..5f223dc 100644
--- a/tests/test_subscriber.vty
+++ b/tests/test_subscriber.vty
@@ -8,11 +8,14 @@ OsmoHLR# list
subscriber (imsi|msisdn|id|imei) IDENT delete
subscriber (imsi|msisdn|id|imei) IDENT update msisdn (none|MSISDN)
subscriber (imsi|msisdn|id|imei) IDENT update aud2g none
- subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI
+ subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor-2g) ki KI
subscriber (imsi|msisdn|id|imei) IDENT update aud3g none
- subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]
+ subscriber (imsi|msisdn|id|imei) IDENT update aud3g (milenage|tuak) k K (op|opc) OP_C [ind-bitlen] [<0-28>]
+ subscriber (imsi|msisdn|id|imei) IDENT update aud3g xor-3g k K [ind-bitlen] [<0-28>]
subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)
subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)
+ show mslookup services
+...
OsmoHLR# subscriber?
subscriber Subscriber management commands
@@ -141,7 +144,7 @@ OsmoHLR# subscriber imsi 123456789023000 update aud2g ?
comp128v1 Use COMP128v1 algorithm
comp128v2 Use COMP128v2 algorithm
comp128v3 Use COMP128v3 algorithm
- xor Use XOR algorithm
+ xor-2g Use XOR-2G algorithm
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ?
ki Set Ki Encryption Key
@@ -152,12 +155,12 @@ OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki ?
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki val ?
<cr>
-OsmoHLR# subscriber imsi 123456789023000 update aud2g xor ki Deaf0ff1ceD0d0DabbedD1ced1ceF00d
+OsmoHLR# subscriber imsi 123456789023000 update aud2g xor-2g ki Deaf0ff1ceD0d0DabbedD1ced1ceF00d
OsmoHLR# subscriber imsi 123456789023000 show
ID: 101
IMSI: 123456789023000
MSISDN: 423
- 2G auth: XOR
+ 2G auth: XOR-2G
KI=deaf0ff1ced0d0dabbedd1ced1cef00d
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
@@ -238,7 +241,7 @@ OsmoHLR# subscriber id 101 show
2G auth: COMP128v3
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
-OsmoHLR# subscriber id 101 update aud2g xor ki CoiffedCicadaeAcidifiedAcaciaBoa
+OsmoHLR# subscriber id 101 update aud2g xor-2g ki CoiffedCicadaeAcidifiedAcaciaBoa
% Invalid value for KI: 'CoiffedCicadaeAcidifiedAcaciaBoa'
OsmoHLR# subscriber id 101 show
ID: 101
@@ -247,7 +250,7 @@ OsmoHLR# subscriber id 101 show
2G auth: COMP128v3
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
-OsmoHLR# subscriber id 101 update aud2g xor ki C01ffedC1cadaeAc1d1f1edAcac1aB0aX
+OsmoHLR# subscriber id 101 update aud2g xor-2g ki C01ffedC1cadaeAc1d1f1edAcac1aB0aX
% Invalid value for KI: 'C01ffedC1cadaeAc1d1f1edAcac1aB0aX'
OsmoHLR# subscriber id 101 show
ID: 101
@@ -266,19 +269,21 @@ OsmoHLR# subscriber id 101 show
OsmoHLR# subscriber imsi 123456789023000 update aud3g ?
none Delete 3G authentication data
milenage Use Milenage algorithm
+ tuak Use TUAK algorithm
+ xor-3g Use XOR-3G algorithm
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage ?
k Set Encryption Key K
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k ?
- K K as 32 hexadecimal characters
+ K K as 32/64 hexadecimal characters
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d ?
op Set OP key
opc Set OPC key
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc ?
- OP_C OP or OPC as 32 hexadecimal characters
+ OP_C OP or OPC as 32/64 hexadecimal characters
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CededEffacedAceFacedBadFadedBeef ?
[ind-bitlen] Set IND bit length
diff --git a/tests/test_subscriber_errors.ctrl b/tests/test_subscriber_errors.ctrl
index 991d3df..2ae9b69 100644
--- a/tests/test_subscriber_errors.ctrl
+++ b/tests/test_subscriber_errors.ctrl
@@ -105,3 +105,51 @@ GET 46 subscriber.by-imsi-1234567890123456.ps-enabled
ERROR 46 Invalid value part of 'by-xxx-value' selector.
GET 47 subscriber.by-imsi-1234567890123456.cs-enabled
ERROR 47 Invalid value part of 'by-xxx-value' selector.
+
+GET 48 subscriber.by-id-0x0123.info
+ERROR 48 Invalid value part of 'by-xxx-value' selector.
+
+SET 49 subscriber.create zzz
+ERROR 49 Invalid IMSI value.
+
+SET 50 subscriber.create 901990000000001
+ERROR 50 Subscriber already exists.
+
+SET 51 subscriber.by-imsi-1234567890123456.msisdn hellobadmsisdn
+ERROR 51 Value failed verification.
+
+SET 52 subscriber.delete 100000
+ERROR 52 Subscriber doesn't exist.
+
+SET 53 subscriber.delete zzz
+ERROR 53 Invalid IMSI value.
+
+SET 54 subscriber.by-imsi-901990000000003.aud2g foobar
+ERROR 54 Value failed verification.
+
+SET 55 subscriber.by-imsi-901990000000003.aud2g foobar,2134
+ERROR 55 Unknown auth algorithm.
+
+SET 56 subscriber.by-imsi-901990000000003.aud2g xor-2g,2134
+ERROR 56 Invalid KI.
+
+SET 57 subscriber.by-imsi-901990000000003.aud3g foobar
+ERROR 57 Value failed verification.
+
+SET 58 subscriber.by-imsi-901990000000003.aud3g foobar,2134
+ERROR 58 Unknown auth algorithm.
+
+SET 59 subscriber.by-imsi-901990000000003.aud3g milenage,2134
+ERROR 59 Invalid KI.
+
+SET 60 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,AAA
+ERROR 60 Invalid format.
+
+SET 61 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC
+ERROR 61 Invalid format.
+
+SET 62 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,zzz
+ERROR 62 Invalid OP/OPC.
+
+SET 63 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,
+ERROR 63 Invalid format.
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 70ae7ae..65f90b4 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -22,13 +22,6 @@ cat $abs_srcdir/gsup/gsup_test.err > experr
AT_CHECK([$abs_top_builddir/tests/gsup/gsup_test], [], [expout], [experr])
AT_CLEANUP
-AT_SETUP([gsup_server])
-AT_KEYWORDS([gsup_server])
-cat $abs_srcdir/gsup_server/gsup_server_test.ok > expout
-cat $abs_srcdir/gsup_server/gsup_server_test.err > experr
-AT_CHECK([$abs_top_builddir/tests/gsup_server/gsup_server_test], [], [expout], [experr])
-AT_CLEANUP
-
AT_SETUP([db])
AT_KEYWORDS([db])
cat $abs_srcdir/db/db_test.ok > expout
@@ -36,3 +29,39 @@ cat $abs_srcdir/db/db_test.err > experr
sqlite3 db_test.db < $abs_top_srcdir/sql/hlr.sql
AT_CHECK([$abs_top_builddir/tests/db/db_test], [], [expout], [experr])
AT_CLEANUP
+
+# AT_SKIP_IF: disable for old sqlite versions, because the way we dump tables in the test doesn't work with it.
+# https://lists.osmocom.org/pipermail/openbsc/2019-November/013063.html
+AT_SETUP([db_upgrade])
+AT_SKIP_IF([ ! pkg-config sqlite3 --exists --atleast-version=3.16.2 ])
+AT_KEYWORDS([db_upgrade])
+cat $abs_srcdir/db_upgrade/db_upgrade_test.ok > expout
+cat $abs_srcdir/db_upgrade/db_upgrade_test.err > experr
+AT_CHECK([$abs_srcdir/db_upgrade/db_upgrade_test.sh $abs_srcdir/db_upgrade $abs_builddir/db_upgrade], [], [expout], [experr])
+AT_CLEANUP
+
+AT_SETUP([mdns])
+AT_KEYWORDS([mdns])
+cat $abs_srcdir/mslookup/mdns_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/mslookup/mdns_test], [0], [ignore], [experr])
+AT_CLEANUP
+
+AT_SETUP([mslookup])
+AT_KEYWORDS([mslookup])
+cat $abs_srcdir/mslookup/mslookup_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/mslookup/mslookup_test], [0], [ignore], [experr])
+AT_CLEANUP
+
+AT_SETUP([mslookup_client])
+AT_KEYWORDS([mslookup_client])
+cat $abs_srcdir/mslookup/mslookup_client_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/mslookup/mslookup_client_test], [0], [ignore], [experr])
+AT_CLEANUP
+
+# AT_SKIP_IF: disable without --enable-mslookup-client-mdns-test (OS#4385)
+AT_SETUP([mslookup_client_mdns])
+AT_SKIP_IF([! test -e $abs_top_builddir/tests/mslookup/mslookup_client_mdns_test ])
+AT_KEYWORDS([mslookup_client_mdns])
+cat $abs_srcdir/mslookup/mslookup_client_mdns_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/mslookup/mslookup_client_mdns_test], [0], [ignore], [experr])
+AT_CLEANUP