pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-gprs/+/37726?usp=email )
Change subject: tests/gmm: Introduce skeleton for gmm_prim_network tests ......................................................................
tests/gmm: Introduce skeleton for gmm_prim_network tests
A new skeleton to add tests for the network (SGSN) mode is added.
Related: OS#5852 Change-Id: I832f16f598f49c18455531fac75367376a3065e6 --- M tests/gmm/Makefile.am M tests/gmm/gmm_prim_ms_test.c A tests/gmm/gmm_prim_network_test.c A tests/gmm/gmm_prim_network_test.err A tests/gmm/gmm_prim_network_test.ok A tests/gmm/gmm_prim_test.h M tests/testsuite.at 7 files changed, 366 insertions(+), 40 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-gprs refs/changes/26/37726/1
diff --git a/tests/gmm/Makefile.am b/tests/gmm/Makefile.am index c84c879..ad565a6 100644 --- a/tests/gmm/Makefile.am +++ b/tests/gmm/Makefile.am @@ -15,6 +15,7 @@ check_PROGRAMS = \ gmm_misc_test \ gmm_prim_ms_test \ + gmm_prim_network_test \ $(NULL)
EXTRA_DIST = \ @@ -22,6 +23,8 @@ gmm_misc_test.ok \ gmm_prim_ms_test.err \ gmm_prim_ms_test.ok \ + gmm_prim_network_test.err \ + gmm_prim_network_test.ok \ $(NULL)
# libosmo-gprs-gmm.a is used below to access non-exported private symbols used in the test: @@ -53,3 +56,20 @@ -Wl,--wrap=osmo_get_rand_id \ -no-install \ $(NULL) + +# libosmo-gprs-llc.a is used below to access non-exported private symbols used in the test: +# libosmo-gprs-rlcmac.a is used below to access non-exported private symbols used in the test: +gmm_prim_network_test_SOURCES = gmm_prim_network_test.c +gmm_prim_network_test_LDADD = \ + $(top_builddir)/src/gmm/libosmo-gprs-gmm.la \ + $(top_builddir)/src/llc/.libs/libosmo-gprs-llc.a \ + $(top_builddir)/src/rlcmac/.libs/libosmo-gprs-rlcmac.a \ + $(top_builddir)/src/csn1/libosmo-csn1.la \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(NULL) + +gmm_prim_network_test_LDFLAGS = \ + -Wl,--wrap=osmo_get_rand_id \ + -no-install \ + $(NULL) diff --git a/tests/gmm/gmm_prim_ms_test.c b/tests/gmm/gmm_prim_ms_test.c index c33bddc..dcbd31a 100644 --- a/tests/gmm/gmm_prim_ms_test.c +++ b/tests/gmm/gmm_prim_ms_test.c @@ -1,4 +1,4 @@ -/* gmm_prim tests +/* gmm_prim tests (MS side) * * (C) 2023 by sysmocom - s.f.m.c. GmbH info@sysmocom.de * Author: Pau espin Pedrol pespin@sysmocom.de @@ -28,8 +28,6 @@ #include <osmocom/core/utils.h> #include <osmocom/core/fsm.h> #include <osmocom/core/msgb.h> -#include <osmocom/core/timer.h> -#include <osmocom/core/timer_compat.h> #include <osmocom/core/select.h>
#include <osmocom/gprs/rlcmac/rlcmac_private.h> @@ -39,6 +37,8 @@ #include <osmocom/gprs/gmm/gmm_prim.h> #include <osmocom/gprs/gmm/gmm_pdu.h>
+#include "gmm_prim_test.h" + static void *tall_ctx = NULL;
/* @@ -189,43 +189,6 @@ return 0; }
-#define clock_debug(fmt, args...) \ - do { \ - struct timespec ts; \ - struct timeval tv; \ - osmo_clock_gettime(CLOCK_MONOTONIC, &ts); \ - osmo_gettimeofday(&tv, NULL); \ - fprintf(stdout, "sys={%lu.%06lu}, mono={%lu.%06lu}: " fmt "\n", \ - tv.tv_sec, tv.tv_usec, ts.tv_sec, ts.tv_nsec/1000, ##args); \ - } while (0) - -static void clock_override_enable(bool enable) -{ - osmo_gettimeofday_override = enable; - osmo_clock_override_enable(CLOCK_MONOTONIC, enable); -} - -static void clock_override_set(long sec, long usec) -{ - struct timespec *mono; - osmo_gettimeofday_override_time.tv_sec = sec; - osmo_gettimeofday_override_time.tv_usec = usec; - mono = osmo_clock_override_gettimespec(CLOCK_MONOTONIC); - mono->tv_sec = sec; - mono->tv_nsec = usec*1000; - - clock_debug("clock_override_set"); -} - -static void clock_override_add_debug(long sec, long usec, bool dbg) -{ - osmo_gettimeofday_override_add(sec, usec); - osmo_clock_override_add(CLOCK_MONOTONIC, sec, usec*1000); - if (dbg) - clock_debug("clock_override_add"); -} -#define clock_override_add(sec, usec) clock_override_add_debug(sec, usec, true) - int test_gmm_prim_up_cb(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) { const char *pdu_name = osmo_gprs_gmm_prim_name(gmm_prim); diff --git a/tests/gmm/gmm_prim_network_test.c b/tests/gmm/gmm_prim_network_test.c new file mode 100644 index 0000000..6e8a053 --- /dev/null +++ b/tests/gmm/gmm_prim_network_test.c @@ -0,0 +1,276 @@ +/* gmm_prim tests (network side) + * + * (C) 2023 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * Author: Pau espin Pedrol pespin@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 <stdint.h> +#include <stdio.h> + +#include <osmocom/core/application.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/fsm.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/select.h> + +#include <osmocom/gprs/rlcmac/rlcmac_private.h> +#include <osmocom/gprs/llc/llc_prim.h> +#include <osmocom/gprs/llc/llc_private.h> +#include <osmocom/gprs/gmm/gmm.h> +#include <osmocom/gprs/gmm/gmm_prim.h> +#include <osmocom/gprs/gmm/gmm_pdu.h> + +#include "gmm_prim_test.h" + +static void *tall_ctx = NULL; + +static uint8_t pdu_gmm_att_req[] = { /* TODO: provide good hexstring, this comes from a att_accept... */ +0x08, 0x02, 0x01, 0x2a, 0x44, 0x32, 0xf4, 0x07, 0x00, 0x05, 0x00, 0x17, 0x16, 0x18, 0x05, 0xf4, +0xea, 0x71, 0x1b, 0x41 +}; + +static uint8_t pdu_gmm_id_resp[] = { /* TODO: provide GMM Identification Response here */ +}; + +/* override, requires '-Wl,--wrap=osmo_get_rand_id' */ +int __real_osmo_get_rand_id(uint8_t *data, size_t len); +int __wrap_osmo_get_rand_id(uint8_t *data, size_t len) +{ + memset(data, 0x00, len); + return 0; +} + +int test_gmm_prim_up_cb(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) +{ + const char *pdu_name = osmo_gprs_gmm_prim_name(gmm_prim); + struct osmo_gprs_gmm_prim *gmm_prim_tx; + int rc; + + switch (gmm_prim->oph.sap) { + case OSMO_GPRS_GMM_SAP_GMMREG: + switch (OSMO_PRIM_HDR(&gmm_prim->oph)) { + case OSMO_PRIM(OSMO_GPRS_GMM_GMMREG_ATTACH, PRIM_OP_CONFIRM): + if (gmm_prim->gmmreg.attach_cnf.accepted) { + printf("%s(): Rx %s accepted=%u allocated_ptmsi=0x%08x allocated_ptmsi_sig=0x%06x allocated_tlli=0x%08x\n", __func__, pdu_name, + gmm_prim->gmmreg.attach_cnf.accepted, + gmm_prim->gmmreg.attach_cnf.acc.allocated_ptmsi, + gmm_prim->gmmreg.attach_cnf.acc.allocated_ptmsi_sig, + gmm_prim->gmmreg.attach_cnf.acc.allocated_tlli); + } else { + printf("%s(): Rx %s accepted=%u rej_cause=%u\n", __func__, pdu_name, + gmm_prim->gmmreg.attach_cnf.accepted, + gmm_prim->gmmreg.attach_cnf.rej.cause); + } + break; + case OSMO_PRIM(OSMO_GPRS_GMM_GMMREG_DETACH, PRIM_OP_CONFIRM): + printf("%s(): Rx %s detach_type='%s'\n", __func__, pdu_name, + osmo_gprs_gmm_detach_ms_type_name(gmm_prim->gmmreg.detach_cnf.detach_type)); + break; + case OSMO_PRIM(OSMO_GPRS_GMM_GMMREG_SIM_AUTH, PRIM_OP_INDICATION): + printf("%s(): Rx %s ac_ref_nr=%u key_seq=%u rand=%s\n", + __func__, pdu_name, + gmm_prim->gmmreg.sim_auth_ind.ac_ref_nr, + gmm_prim->gmmreg.sim_auth_ind.key_seq, + osmo_hexdump(gmm_prim->gmmreg.sim_auth_ind.rand, + sizeof(gmm_prim->gmmreg.sim_auth_ind.rand))); + /* Emulate SIM, asnwer SRES=0xacacacac, Kc=bdbdbd... */ + gmm_prim_tx = osmo_gprs_gmm_prim_alloc_gmmreg_sim_auth_rsp(); + OSMO_ASSERT(gmm_prim_tx); + gmm_prim_tx->gmmreg.sim_auth_rsp.ac_ref_nr = gmm_prim->gmmreg.sim_auth_ind.ac_ref_nr; + gmm_prim_tx->gmmreg.sim_auth_rsp.key_seq = gmm_prim->gmmreg.sim_auth_ind.key_seq; + memcpy(gmm_prim_tx->gmmreg.sim_auth_rsp.rand, gmm_prim->gmmreg.sim_auth_ind.rand, + sizeof(gmm_prim_tx->gmmreg.sim_auth_rsp.rand)); + memset(gmm_prim_tx->gmmreg.sim_auth_rsp.sres, 0xac, + sizeof(gmm_prim_tx->gmmreg.sim_auth_rsp.sres)); + memset(gmm_prim_tx->gmmreg.sim_auth_rsp.kc, 0xbd, + sizeof(gmm_prim_tx->gmmreg.sim_auth_rsp.kc)); + rc = osmo_gprs_gmm_prim_upper_down(gmm_prim_tx); + OSMO_ASSERT(rc == 0); + break; + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0) + } + break; + case OSMO_GPRS_GMM_SAP_GMMSM: + switch (OSMO_PRIM_HDR(&gmm_prim->oph)) { + case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_ESTABLISH, PRIM_OP_CONFIRM): + if (gmm_prim->gmmsm.establish_cnf.accepted) + printf("%s(): Rx %s sess_id=%u accepted\n", __func__, pdu_name, + gmm_prim->gmmsm.sess_id); + else + printf("%s(): Rx %s sess_id=%u rejected cause=%u\n", __func__, pdu_name, + gmm_prim->gmmsm.sess_id, + gmm_prim->gmmsm.establish_cnf.rej.cause); + break; + case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_UNITDATA, PRIM_OP_INDICATION): + printf("%s(): Rx %s sess_id=%u sm_pdu=%s\n", __func__, pdu_name, + gmm_prim->gmmsm.sess_id, + osmo_hexdump(gmm_prim->gmmsm.unitdata_ind.smpdu, + gmm_prim->gmmsm.unitdata_ind.smpdu_len)); + break; + case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_RELEASE, PRIM_OP_INDICATION): + printf("%s(): Rx %s sess_id=%u\n", __func__, pdu_name, + gmm_prim->gmmsm.sess_id); + break; + case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_MODIFY, PRIM_OP_INDICATION): + printf("%s(): Rx %s sess_id=%u allocated_ptmsi=0x%08x allocated_ptmsi_sig=0x%06x allocated_tlli=0x%08x\n", __func__, pdu_name, + gmm_prim->gmmsm.sess_id, + gmm_prim->gmmsm.modify_ind.allocated_ptmsi, + gmm_prim->gmmsm.modify_ind.allocated_ptmsi_sig, + gmm_prim->gmmsm.modify_ind.allocated_tlli); + break; + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0) + } + break; + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0); + } + return 0; +} + +int test_gmm_prim_down_cb(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) +{ + const char *pdu_name = osmo_gprs_gmm_prim_name(gmm_prim); + + switch (gmm_prim->oph.sap) { + case OSMO_GPRS_GMM_SAP_GMMBSSGP: + switch (OSMO_PRIM_HDR(&gmm_prim->oph)) { + case OSMO_PRIM(OSMO_GPRS_GMM_GMMBSSGP_PAGING, PRIM_OP_REQUEST): + case OSMO_PRIM(OSMO_GPRS_GMM_GMMBSSGP_RA_CAPABILITY, PRIM_OP_REQUEST): + case OSMO_PRIM(OSMO_GPRS_GMM_GMMBSSGP_RA_CAPABILITY_UPDATE, PRIM_OP_RESPONSE): + case OSMO_PRIM(OSMO_GPRS_GMM_GMMBSSGP_MS_REGISTRATION_ENQUIRY, PRIM_OP_RESPONSE): + printf("%s(): Rx %s\n", __func__, pdu_name); + break; + } + break; + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0); + } + return 0; +} + +int test_gmm_prim_llc_down_cb(struct osmo_gprs_llc_prim *llc_prim, void *user_data) +{ + const char *pdu_name = osmo_gprs_llc_prim_name(llc_prim); + struct osmo_gprs_gmm_prim *gmm_prim_tx; + + switch (llc_prim->oph.sap) { + case OSMO_GPRS_LLC_SAP_LLGMM: + switch (OSMO_PRIM_HDR(&llc_prim->oph)) { + case OSMO_PRIM(OSMO_GPRS_LLC_LLGMM_ASSIGN, PRIM_OP_REQUEST): + printf("%s(): Rx %s old_TLLI=0x%08x new_TLLI=0x%08x\n", + __func__, pdu_name, + llc_prim->llgmm.tlli, llc_prim->llgmm.assign_req.tlli_new); + break; + default: + printf("%s(): Rx %s TLLI=0x%08x\n", __func__, pdu_name, llc_prim->llgmm.tlli); + } + break; + case OSMO_GPRS_LLC_SAP_LL: + printf("%s(): Rx %s TLLI=0x%08x SAPI=%s l3=[%s]\n", __func__, pdu_name, + llc_prim->ll.tlli, osmo_gprs_llc_sapi_name(llc_prim->ll.sapi), + osmo_hexdump(llc_prim->ll.l3_pdu, llc_prim->ll.l3_pdu_len)); + switch (OSMO_PRIM_HDR(&llc_prim->oph)) { + case OSMO_PRIM(OSMO_GPRS_LLC_LL_UNITDATA, PRIM_OP_REQUEST): + /* Immediately notify GMM that it was transmitted over the air: */ + gmm_prim_tx = (struct osmo_gprs_gmm_prim *)gprs_rlcmac_prim_alloc_gmmrr_llc_transmitted_ind(llc_prim->ll.tlli); + gmm_prim_tx->oph.sap = OSMO_GPRS_GMM_SAP_GMMRR; + gmm_prim_tx->oph.primitive = OSMO_GPRS_GMM_GMMRR_LLC_TRANSMITTED; + osmo_gprs_gmm_prim_lower_up(gmm_prim_tx); + break; + } + break; + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0); + } + return 0; +} + +/* Test explicit GPRS attach through GMMREG, TS 24.007 Annex C.1 */ +static void test_gmm_prim_ms_gmmreg(void) +{ + //struct osmo_gprs_gmm_prim *gmm_prim; + struct osmo_gprs_llc_prim *llc_prim; + int rc; + uint32_t rand_tlli = 0x80001234; + + printf("==== %s() [start] ====\n", __func__); + + clock_override_set(0, 0); + + rc = osmo_gprs_gmm_init(OSMO_GPRS_GMM_LOCATION_NETWORK); + OSMO_ASSERT(rc == 0); + + osmo_gprs_gmm_prim_set_up_cb(test_gmm_prim_up_cb, NULL); + osmo_gprs_gmm_prim_set_down_cb(test_gmm_prim_down_cb, NULL); + osmo_gprs_gmm_prim_set_llc_down_cb(test_gmm_prim_llc_down_cb, NULL); + + /* MS sends GMM Attach Req */ + llc_prim = gprs_llc_prim_alloc_ll_unitdata_ind(rand_tlli, OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_att_req, sizeof(pdu_gmm_att_req)); + OSMO_ASSERT(llc_prim); + rc = osmo_gprs_gmm_prim_llc_lower_up(llc_prim); + /* TODO: implement this primitive! + * OSMO_ASSERT(rc == 0); */ + /* As a result, Network answers with GMM Identification Request. */ + + /* MS sends GMM Identification response */ + llc_prim = gprs_llc_prim_alloc_ll_unitdata_ind(rand_tlli, OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_id_resp, sizeof(pdu_gmm_id_resp)); + OSMO_ASSERT(llc_prim); + rc = osmo_gprs_gmm_prim_llc_lower_up(llc_prim); + /* TODO: implement this primitive! + * OSMO_ASSERT(rc == 0); */ + + /* ... */ + + printf("==== %s() [end] ====\n", __func__); +} + +static const struct log_info_cat test_log_categories[] = { }; +static const struct log_info test_log_info = { + .cat = test_log_categories, + .num_cat = ARRAY_SIZE(test_log_categories), +}; + +int main(int argc, char *argv[]) +{ + tall_ctx = talloc_named_const(NULL, 1, __FILE__); + + osmo_init_logging2(tall_ctx, &test_log_info); + log_parse_category_mask(osmo_stderr_target, "DLGLOBAL,1:"); + osmo_fsm_log_addr(false); + + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_print_category_hex(osmo_stderr_target, 0); + log_set_print_category(osmo_stderr_target, 1); + log_set_print_level(osmo_stderr_target, 1); + log_set_use_color(osmo_stderr_target, 0); + + clock_override_enable(true); + + test_gmm_prim_ms_gmmreg(); + + talloc_free(tall_ctx); +} diff --git a/tests/gmm/gmm_prim_network_test.err b/tests/gmm/gmm_prim_network_test.err new file mode 100644 index 0000000..e73f215 --- /dev/null +++ b/tests/gmm/gmm_prim_network_test.err @@ -0,0 +1,4 @@ +DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication +DLGLOBAL NOTICE Rx LL-UNITDATA.indication: Unknown TLLI 0x80001234 +DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication +DLGLOBAL NOTICE Rx LL-UNITDATA.indication: Unknown TLLI 0x80001234 diff --git a/tests/gmm/gmm_prim_network_test.ok b/tests/gmm/gmm_prim_network_test.ok new file mode 100644 index 0000000..a26ff56 --- /dev/null +++ b/tests/gmm/gmm_prim_network_test.ok @@ -0,0 +1,3 @@ +==== test_gmm_prim_ms_gmmreg() [start] ==== +sys={0.000000}, mono={0.000000}: clock_override_set +==== test_gmm_prim_ms_gmmreg() [end] ==== diff --git a/tests/gmm/gmm_prim_test.h b/tests/gmm/gmm_prim_test.h new file mode 100644 index 0000000..1e231b1 --- /dev/null +++ b/tests/gmm/gmm_prim_test.h @@ -0,0 +1,41 @@ +#pragma once + +#include <osmocom/core/timer.h> +#include <osmocom/core/timer_compat.h> + +#define clock_debug(fmt, args...) \ + do { \ + struct timespec ts; \ + struct timeval tv; \ + osmo_clock_gettime(CLOCK_MONOTONIC, &ts); \ + osmo_gettimeofday(&tv, NULL); \ + fprintf(stdout, "sys={%lu.%06lu}, mono={%lu.%06lu}: " fmt "\n", \ + tv.tv_sec, tv.tv_usec, ts.tv_sec, ts.tv_nsec/1000, ##args); \ + } while (0) + +static void clock_override_enable(bool enable) +{ + osmo_gettimeofday_override = enable; + osmo_clock_override_enable(CLOCK_MONOTONIC, enable); +} + +static void clock_override_set(long sec, long usec) +{ + struct timespec *mono; + osmo_gettimeofday_override_time.tv_sec = sec; + osmo_gettimeofday_override_time.tv_usec = usec; + mono = osmo_clock_override_gettimespec(CLOCK_MONOTONIC); + mono->tv_sec = sec; + mono->tv_nsec = usec*1000; + + clock_debug("clock_override_set"); +} + +static inline void clock_override_add_debug(long sec, long usec, bool dbg) +{ + osmo_gettimeofday_override_add(sec, usec); + osmo_clock_override_add(CLOCK_MONOTONIC, sec, usec*1000); + if (dbg) + clock_debug("clock_override_add"); +} +#define clock_override_add(sec, usec) clock_override_add_debug(sec, usec, true) diff --git a/tests/testsuite.at b/tests/testsuite.at index 3b5c326..e819a8d 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -15,6 +15,13 @@ AT_CHECK([$abs_top_builddir/tests/gmm/gmm_prim_ms_test], [0], [expout], [experr]) AT_CLEANUP
+AT_SETUP([gmm/gmm_prim_network]) +AT_KEYWORDS([gmm gmm_prim_network]) +cat $abs_srcdir/gmm/gmm_prim_network_test.ok > expout +cat $abs_srcdir/gmm/gmm_prim_network_test.err > experr +AT_CHECK([$abs_top_builddir/tests/gmm/gmm_prim_network_test], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([llc/llc]) AT_KEYWORDS([llc llc]) cat $abs_srcdir/llc/llc_test.ok > expout