diff options
Diffstat (limited to 'tests/msc_vlr/msc_vlr_tests.c')
-rw-r--r-- | tests/msc_vlr/msc_vlr_tests.c | 771 |
1 files changed, 410 insertions, 361 deletions
diff --git a/tests/msc_vlr/msc_vlr_tests.c b/tests/msc_vlr/msc_vlr_tests.c index ffe35f7cc..9c3ecb740 100644 --- a/tests/msc_vlr/msc_vlr_tests.c +++ b/tests/msc_vlr/msc_vlr_tests.c @@ -30,19 +30,17 @@ #include <osmocom/core/application.h> #include <osmocom/gsm/protocol/gsm_04_11.h> #include <osmocom/gsm/gsup.h> -#include <osmocom/gsupclient/gsup_client.h> +#include <osmocom/msc/gsup_client_mux.h> #include <osmocom/msc/gsm_04_11.h> #include <osmocom/msc/debug.h> #include <osmocom/msc/gsm_04_08.h> #include <osmocom/msc/transaction.h> -#include <osmocom/msc/a_iface_bssap.h> - -#if BUILD_IU -#include <osmocom/msc/iucs_ranap.h> -#include <osmocom/ranap/iu_client.h> -#else -#include <osmocom/msc/iu_dummy.h> -#endif +#include <osmocom/msc/ran_msg.h> +#include <osmocom/msc/msc_a.h> +#include <osmocom/msc/msc_i.h> +#include <osmocom/msc/msc_t.h> +#include <osmocom/msc/call_leg.h> +#include <osmocom/msc/rtp_stream.h> #include "msc_vlr_tests.h" @@ -80,7 +78,7 @@ const char *cc_to_mncc_tx_expected_imsi = NULL; bool cc_to_mncc_tx_confirmed = false; uint32_t cc_to_mncc_tx_got_callref = 0; -extern int gsm0407_pdisc_ctr_bin(uint8_t pdisc); +extern int ran_dec_dtap_undup_pdisc_ctr_bin(uint8_t pdisc); /* static state variables for the L3 send sequence numbers */ static uint8_t n_sd[4]; @@ -91,7 +89,7 @@ static void patch_l3_seq_nr(struct msgb *msg) struct gsm48_hdr *gh = msgb_l3(msg); uint8_t pdisc = gsm48_hdr_pdisc(gh); uint8_t *msg_type_oct = &msg->l3h[1]; - int bin = gsm0407_pdisc_ctr_bin(pdisc); + int bin = ran_dec_dtap_undup_pdisc_ctr_bin(pdisc); if (bin >= 0 && bin < ARRAY_SIZE(n_sd)) { /* patch in n_sd into the msg_type octet */ @@ -126,21 +124,6 @@ static const char *gh_type_name(struct gsm48_hdr *gh) gsm48_hdr_msg_type(gh)); } -void dtap_expect_tx(const char *hex) -{ - /* Has the previously expected dtap been received? */ - OSMO_ASSERT(!dtap_tx_expected); - if (!hex) - return; - dtap_tx_expected = msgb_from_hex("dtap_tx_expected", 1024, hex); - /* Mask the sequence number out */ - if (msgb_length(dtap_tx_expected) >= 2) - dtap_tx_expected->data[1] &= 0x3f; - dtap_tx_confirmed = false; -} - -int vlr_gsupc_read_cb(struct osmo_gsup_client *gsupc, struct msgb *msg); - void gsup_rx(const char *rx_hex, const char *expect_tx_hex) { int rc; @@ -154,97 +137,303 @@ void gsup_rx(const char *rx_hex, const char *expect_tx_hex) fprintf(stderr, "<-- GSUP rx %s: %s\n", label, osmo_hexdump_nospc(msgb_l2(msg), msgb_l2len(msg))); /* GSUP read cb takes ownership of msgb */ - rc = vlr_gsupc_read_cb(net->vlr->gsup_client, msg); + rc = gsup_client_mux_rx(net->gcm->gsup_client, msg); fprintf(stderr, "<-- GSUP rx %s: vlr_gsupc_read_cb() returns %d\n", label, rc); if (expect_tx_hex) OSMO_ASSERT(gsup_tx_confirmed); } -bool conn_exists(const struct ran_conn *conn) +bool conn_exists(const struct msub *msub) { - struct ran_conn *c; + struct msub *i; - if (!conn) + if (!msub) return false; - llist_for_each_entry(c, &net->ran_conns, entry) { - if (c == conn) + llist_for_each_entry(i, &msub_list, entry) { + if (i == msub) return true; } + btw("msub gone"); return false; } /* Simplified version of the cm_service_request_concludes() */ -void conn_conclude_cm_service_req(struct ran_conn *conn, - enum osmo_rat_type via_ran) +void conn_conclude_cm_service_req(struct msub *msub, const char *cm_service_use) { + int32_t count; + struct msc_a *msc_a = msub_msc_a(msub); btw("Concluding CM Service Request"); - OSMO_ASSERT(conn); - OSMO_ASSERT(conn->received_cm_service_request); + OSMO_ASSERT(conn_exists(msub)); + count = osmo_use_count_by(&msc_a->use_count, cm_service_use); + OSMO_ASSERT(count > 0); - conn->received_cm_service_request = false; - ran_conn_put(conn, RAN_CONN_USE_CM_SERVICE); + OSMO_ASSERT(osmo_use_count_get_put(&msc_a->use_count, cm_service_use, -count) == 0) - ASSERT_RELEASE_CLEAR(via_ran); + ASSERT_RELEASE_CLEAR(msc_a->c.ran->type); } -enum osmo_rat_type rx_from_ran = OSMO_RAT_GERAN_A; +void dummy_msc_i_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ +} + +static const struct osmo_fsm_state dummy_msc_i_states[] = { + { + .name = "0", + .in_event_mask = 0xffffffff, + .action = dummy_msc_i_action, + }, +}; -/* SCCP user stub to make a_iface_tx_bssap() happy during test case execution */ -struct osmo_sccp_user { - uint8_t foo; +struct osmo_fsm dummy_msc_i_fsm = { + .name = "dummy_msc_i", + .states = dummy_msc_i_states, + .num_states = ARRAY_SIZE(dummy_msc_i_states), + .log_subsys = DMSC, + .event_names = msc_i_fsm_event_names, }; -static struct osmo_sccp_user g_scu; -struct ran_conn *conn_new(void) +struct msc_i *dummy_msc_i_alloc(struct msub *msub, struct ran_infra *ran) { - struct ran_conn *conn; - conn = ran_conn_alloc(net, rx_from_ran, 23); - if (conn->via_ran == OSMO_RAT_UTRAN_IU) { - struct ranap_ue_conn_ctx *ue_ctx = talloc_zero(conn, struct ranap_ue_conn_ctx); - *ue_ctx = (struct ranap_ue_conn_ctx){ - .conn_id = 42, - }; - conn->iu.ue_ctx = ue_ctx; - } else { - conn->a.scu = &g_scu; + return msub_role_alloc(g_msub, MSC_ROLE_I, &dummy_msc_i_fsm, struct msc_i, ran); +} + +enum osmo_rat_type rx_from_ran = OSMO_RAT_GERAN_A; + +struct msub *g_msub = NULL; + +void dtap_expect_tx(const char *hex) +{ + /* Has the previously expected dtap been received? */ + OSMO_ASSERT(!dtap_tx_expected); + if (!hex) + return; + dtap_tx_expected = msgb_from_hex("dtap_tx_expected", 1024, hex); + /* Mask the sequence number out */ + if (msgb_length(dtap_tx_expected) >= 2) + dtap_tx_expected->data[1] &= 0x3f; + dtap_tx_confirmed = false; +} + +static int _validate_dtap(struct msgb *msg, enum osmo_rat_type to_ran) +{ + struct gsm48_hdr *gh = (void*)msg->data; + uint8_t pdisc = gsm48_hdr_pdisc(gh); + uint8_t msgt = gsm48_hdr_msg_type(gh); + + btw("DTAP --%s--> MS: %s: %s", + osmo_rat_type_name(to_ran), gh_type_name((void*)msg->data), + osmo_hexdump_nospc(msg->data, msg->len)); + + if (pdisc == GSM48_PDISC_MM + && msgt == GSM48_MT_MM_CM_SERV_ACC) { + cm_service_result_sent |= RES_ACCEPT; + talloc_free(msg); + return 0; + } + + if (pdisc == GSM48_PDISC_MM + && msgt == GSM48_MT_MM_CM_SERV_REJ) { + cm_service_result_sent |= RES_REJECT; + talloc_free(msg); + return 0; + } + + OSMO_ASSERT(dtap_tx_expected); + + /* Mask the sequence number out before comparing */ + msg->data[1] &= 0x3f; + if (!msgb_eq_data_print(msg, dtap_tx_expected->data, dtap_tx_expected->len)) + abort(); + + btw("DTAP matches expected message"); + + talloc_free(msg); + dtap_tx_confirmed = true; + talloc_free(dtap_tx_expected); + dtap_tx_expected = NULL; + + return 0; +} + +static void bssap_validate_clear_cmd() +{ + OSMO_ASSERT(bssap_clear_expected); + bssap_clear_expected = false; + bssap_clear_sent = true; +} + +static void iucs_validate_clear_cmd() +{ + OSMO_ASSERT(iu_release_expected); + iu_release_expected = false; + iu_release_sent = true; +} + +static int bssap_validate_cipher_mode_cmd(const struct ran_cipher_mode_command *cmd) +{ + int i; + const char *got_key; + cipher_mode_cmd_sent = true; + cipher_mode_cmd_sent_with_imeisv = cmd->geran.retrieve_imeisv; + btw("sending Ciphering Mode Command: retrieve_imeisv=%d", cipher_mode_cmd_sent_with_imeisv); + for (i = 0; i < 7; i++) { + if (!(cmd->geran.a5_encryption_mask & (1 << i))) + continue; + btw("...perm algo: A5/%d", i); + } + got_key = osmo_hexdump_nospc(cmd->vec->kc, sizeof(cmd->vec->kc)); + btw("...key: %s", got_key); + + if (!cipher_mode_expect_kc + || strcmp(cipher_mode_expect_kc, got_key)) { + log("FAILURE: expected kc=%s", cipher_mode_expect_kc ? : "NULL"); + OSMO_ASSERT(false); } - return conn; + return 0; } -struct ran_conn *g_conn = NULL; +static int iucs_validate_security_mode_ctrl(const struct ran_cipher_mode_command *cmd) +{ + const char *got_ik; + got_ik = osmo_hexdump_nospc(cmd->vec->ik, sizeof(cmd->vec->ik)); + btw("sending SecurityModeControl: ik=%s", got_ik); + security_mode_ctrl_sent = true; + if (!security_mode_expect_ik + || strcmp(security_mode_expect_ik, got_ik)) { + log("FAILURE: expected ik=%s", security_mode_expect_ik ? : "NULL"); + OSMO_ASSERT(false); + } + return 0; +} -void rx_from_ms(struct msgb *msg) +struct msgb *dont_ran_encode(struct osmo_fsm_inst *caller_fi, const struct ran_msg *ran_enc_msg) { - struct gsm48_hdr *gh = msgb_l3(msg); + struct msc_role_common *c = caller_fi->priv; + enum osmo_rat_type ran_type = c->ran->type; + const char *ran_name = osmo_rat_type_name(ran_type); + LOG_RAN_ENC(caller_fi, DMSC, LOGL_INFO, "%s on %s\n", ran_msg_type_name(ran_enc_msg->msg_type), + ran_name); + + switch (ran_enc_msg->msg_type) { + case RAN_MSG_DTAP: + _validate_dtap(ran_enc_msg->dtap, ran_type); + break; + case RAN_MSG_CLEAR_COMMAND: + switch (ran_type) { + case OSMO_RAT_GERAN_A: + bssap_validate_clear_cmd(); + break; + case OSMO_RAT_UTRAN_IU: + iucs_validate_clear_cmd(); + break; + default: + OSMO_ASSERT(false); + } + break; + case RAN_MSG_CIPHER_MODE_COMMAND: + switch (ran_type) { + case OSMO_RAT_GERAN_A: + bssap_validate_cipher_mode_cmd(&ran_enc_msg->cipher_mode_command); + break; + case OSMO_RAT_UTRAN_IU: + iucs_validate_security_mode_ctrl(&ran_enc_msg->cipher_mode_command); + break; + default: + OSMO_ASSERT(false); + } + break; + default: + break; + } - log("MSC <--%s-- MS: %s", - osmo_rat_type_name(rx_from_ran), - gh_type_name(gh)); + /* We're testing MSC and VLR interaction, not message encoding. + * Return whatever. The test msc_i instance is a dummy and drops these. + * But it must be msg_free()-able. + */ + return msgb_alloc(1, "unused dummy msg"); +} + +struct ran_infra test_ran_infra[] = { + [OSMO_RAT_GERAN_A] = { + .type = OSMO_RAT_GERAN_A, + .an_proto = OSMO_GSUP_ACCESS_NETWORK_PROTOCOL_TS3G_48006, + .log_subsys = DBSSAP, + .tdefs = msc_tdefs_geran, + .ran_encode = dont_ran_encode, + }, + [OSMO_RAT_UTRAN_IU] = { + .type = OSMO_RAT_UTRAN_IU, + .an_proto = OSMO_GSUP_ACCESS_NETWORK_PROTOCOL_TS3G_25413, + .log_subsys = DIUCS, + .tdefs = msc_tdefs_utran, + .ran_encode = dont_ran_encode, + }, +}; - if (!conn_exists(g_conn)) - g_conn = NULL; +static int fake_msc_a_ran_dec(const struct ran_msg *ran_dec_msg) +{ + struct msc_a_ran_dec_data d = { + .from_role = MSC_ROLE_I, + }; + return msc_a_ran_decode_cb(g_msub->role[MSC_ROLE_A], &d, ran_dec_msg); +} - if (!g_conn) { +void rx_from_ms(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + struct ran_msg ran_dec_msg; + struct gsm0808_cell_id cell_id = { + .id_discr = CELL_IDENT_LAI_AND_LAC, + .id.lai_and_lac = { + .plmn = { + .mcc = 1, + .mnc = 2, + }, + .lac = 23, + }, + }; + struct msc_a *msc_a; + + log("MSC <--%s-- MS: %s", osmo_rat_type_name(rx_from_ran), gh_type_name(gh)); + + if (!conn_exists(g_msub)) + g_msub = NULL; + + if (!g_msub) { log("new conn"); - g_conn = conn_new(); + g_msub = msub_alloc(net); + msc_a_alloc(g_msub, &test_ran_infra[rx_from_ran]); + dummy_msc_i_alloc(g_msub, &test_ran_infra[rx_from_ran]); + reset_l3_seq_nr(); - patch_l3_seq_nr(msg); - ran_conn_compl_l3(g_conn, msg, 23); + ran_dec_msg = (struct ran_msg){ + .msg_type = RAN_MSG_COMPL_L3, + .compl_l3 = { + .cell_id = &cell_id, + .msg = msg, + }, + }; } else { - patch_l3_seq_nr(msg); - if ((gsm48_hdr_pdisc(gh) == GSM48_PDISC_RR) - && (gsm48_hdr_msg_type(gh) == GSM48_MT_RR_CIPH_M_COMPL)) - ran_conn_cipher_mode_compl(g_conn, msg, 0); - else - ran_conn_dtap(g_conn, msg); + ran_dec_msg = (struct ran_msg){ + .msg_type = RAN_MSG_DTAP, + .dtap = msg, + }; } - if (!conn_exists(g_conn)) - g_conn = NULL; + msc_a = msub_msc_a(g_msub); + msc_a_get(msc_a, __func__); + + patch_l3_seq_nr(msg); + fake_msc_a_ran_dec(&ran_dec_msg); + + msc_a_put(msc_a, __func__); + + if (!conn_exists(g_msub)) + g_msub = NULL; } void ms_sends_msg(const char *hex) @@ -257,34 +446,21 @@ void ms_sends_msg(const char *hex) msgb_free(msg); } -void bss_sends_bssap_mgmt(const char *hex) +void ms_sends_classmark_update(const struct osmo_gsm48_classmark *classmark) { - struct msgb *msg; - struct bssmap_header *bh; - struct a_conn_info a_conn_info; - - msg = msgb_from_hex("bss_sends_bssap_mgmt", 1024, hex); - msg->l3h = msg->data; - - msg->l2h = msgb_push(msg, sizeof(*bh)); - bh = (void*)msg->l2h; - bh->type = BSSAP_MSG_BSS_MANAGEMENT; - bh->length = msgb_l3len(msg); - - if (!conn_exists(g_conn)) - g_conn = NULL; - - OSMO_ASSERT(g_conn); - a_conn_info.network = net; - a_conn_info.conn_id = g_conn->a.conn_id; - - a_sccp_rx_dt((struct osmo_sccp_user*)0x1, &a_conn_info, msg); - msgb_free(msg); + struct ran_msg ran_dec = { + .msg_type = RAN_MSG_CLASSMARK_UPDATE, + .classmark_update = { + .classmark = classmark, + }, + }; + fake_msc_a_ran_dec(&ran_dec); } static int ms_sends_msg_fake(uint8_t pdisc, uint8_t msg_type) { int rc; + struct ran_msg ran_dec; struct msgb *msg; struct gsm48_hdr *gh; @@ -298,7 +474,12 @@ static int ms_sends_msg_fake(uint8_t pdisc, uint8_t msg_type) msgb_put(msg, 123); patch_l3_seq_nr(msg); - rc = gsm0408_dispatch(g_conn, msg); + + ran_dec = (struct ran_msg){ + .msg_type = RAN_MSG_DTAP, + .dtap = msg, + }; + rc = fake_msc_a_ran_dec(&ran_dec); talloc_free(msg); return rc; @@ -352,7 +533,6 @@ void __wrap_gsm340_gen_scts(uint8_t *scts, time_t time) const char *paging_expecting_imsi = NULL; uint32_t paging_expecting_tmsi; bool paging_sent; -bool paging_stopped; void paging_expect_imsi(const char *imsi) { @@ -366,69 +546,25 @@ void paging_expect_tmsi(uint32_t tmsi) paging_expecting_imsi = NULL; } -static int _paging_sent(enum osmo_rat_type via_ran, const char *imsi, uint32_t tmsi, uint32_t lac) +/* override, requires '-Wl,--wrap=ran_peers_down_paging' */ +int __real_ran_peers_down_paging(struct sccp_ran_inst *sri, enum CELL_IDENT page_where, struct vlr_subscr *vsub, + enum paging_cause cause); +int __wrap_ran_peers_down_paging(struct sccp_ran_inst *sri, enum CELL_IDENT page_where, struct vlr_subscr *vsub, + enum paging_cause cause) { - log("%s sends out paging request to IMSI %s, TMSI 0x%08x, LAC %u", - osmo_rat_type_name(via_ran), imsi, tmsi, lac); + log("paging request (%s) to %s on %s", paging_cause_name(cause), vlr_subscr_name(vsub), + osmo_rat_type_name(sri->ran->type)); + OSMO_ASSERT(paging_expecting_imsi || (paging_expecting_tmsi != GSM_RESERVED_TMSI)); if (paging_expecting_imsi) - VERBOSE_ASSERT(strcmp(paging_expecting_imsi, imsi), == 0, "%d"); + VERBOSE_ASSERT(strcmp(paging_expecting_imsi, vsub->imsi), == 0, "%d"); if (paging_expecting_tmsi != GSM_RESERVED_TMSI) { - VERBOSE_ASSERT(paging_expecting_tmsi, == tmsi, "0x%08x"); + VERBOSE_ASSERT(paging_expecting_tmsi, == vsub->tmsi, "0x%08x"); } paging_sent = true; - paging_stopped = false; return 1; } -/* override, requires '-Wl,--wrap=ranap_iu_page_cs' */ -int __real_ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac); -int __wrap_ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac) -{ - return _paging_sent(OSMO_RAT_UTRAN_IU, imsi, tmsi ? *tmsi : GSM_RESERVED_TMSI, lac); -} - -/* override, requires '-Wl,--wrap=a_iface_tx_paging' */ -int __real_a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac); -int __wrap_a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac) -{ - return _paging_sent(OSMO_RAT_GERAN_A, imsi, tmsi, lac); -} - -/* override, requires '-Wl,--wrap=msc_stop_paging' */ -void __real_msc_stop_paging(struct vlr_subscr *vsub); -void __wrap_msc_stop_paging(struct vlr_subscr *vsub) -{ - paging_stopped = true; -} - - -/* override, requires '-Wl,--wrap=osmo_sccp_tx_data_msg' */ -int __real_osmo_sccp_tx_data_msg(struct osmo_sccp_user *scu, uint32_t conn_id, - struct msgb *msg); -int __wrap_osmo_sccp_tx_data_msg(struct osmo_sccp_user *scu, uint32_t conn_id, - struct msgb *msg) -{ - const char *proto_str; - const char *msg_str = gsm0808_bssmap_name(msg->l3h[2]); - switch (*msg->l3h) { - case BSSAP_MSG_BSS_MANAGEMENT: - proto_str = "BSSAP-BSS-MANAGEMENT"; - break; - case BSSAP_MSG_DTAP: - proto_str = "BSSAP-DTAP"; - break; - default: - proto_str = ""; - msg_str = ""; - break; - } - - log("BSC <--%s-- MSC: %s %s", proto_str, msg_str, msgb_hexdump(msg)); - msgb_free(msg); - return 0; -} - void clear_vlr() { struct vlr_subscr *vsub, *n; @@ -531,12 +667,26 @@ static struct log_info info = { .num_cat = ARRAY_SIZE(test_categories), }; +struct gsm_mncc *on_call_release_mncc_sends_to_cc_data = NULL; + int mncc_recv(struct gsm_network *net, struct msgb *msg) { struct gsm_mncc *mncc = (void*)msg->data; log("MSC --> MNCC: callref 0x%x: %s", mncc->callref, get_mncc_name(mncc->msg_type)); + if (mncc->msg_type == MNCC_REL_IND && on_call_release_mncc_sends_to_cc_data) { + + log("MNCC: callref 0x%x: Call Release triggering %s", mncc->callref, + get_mncc_name(on_call_release_mncc_sends_to_cc_data->msg_type)); + + mncc_tx_to_cc(net, on_call_release_mncc_sends_to_cc_data->msg_type, + on_call_release_mncc_sends_to_cc_data); + + on_call_release_mncc_sends_to_cc_data = NULL; + return 0; + } + OSMO_ASSERT(cc_to_mncc_tx_expected_msg_type); if (cc_to_mncc_tx_expected_msg_type != mncc->msg_type) { log("Mismatch! Expected MNCC msg type: %s", @@ -600,129 +750,40 @@ int __wrap_osmo_gsup_client_send(struct osmo_gsup_client *gsupc, struct msgb *ms return 0; } -static int _validate_dtap(struct msgb *msg, enum osmo_rat_type to_ran) -{ - btw("DTAP --%s--> MS: %s: %s", - osmo_rat_type_name(to_ran), gh_type_name((void*)msg->data), - osmo_hexdump_nospc(msg->data, msg->len)); - - OSMO_ASSERT(dtap_tx_expected); - - /* Mask the sequence number out before comparing */ - msg->data[1] &= 0x3f; - if (!msgb_eq_data_print(msg, dtap_tx_expected->data, dtap_tx_expected->len)) - abort(); - - btw("DTAP matches expected message"); - - talloc_free(msg); - dtap_tx_confirmed = true; - talloc_free(dtap_tx_expected); - dtap_tx_expected = NULL; - return 0; -} - -/* override, requires '-Wl,--wrap=ranap_iu_tx' */ -int __real_ranap_iu_tx(struct msgb *msg, uint8_t sapi); -int __wrap_ranap_iu_tx(struct msgb *msg, uint8_t sapi) -{ - return _validate_dtap(msg, OSMO_RAT_UTRAN_IU); -} - -/* override, requires '-Wl,--wrap=ranap_iu_tx_release' */ -int __real_ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause); -int __wrap_ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause) -{ - btw("Iu Release --%s--> MS", osmo_rat_type_name(OSMO_RAT_UTRAN_IU)); - OSMO_ASSERT(iu_release_expected); - iu_release_expected = false; - iu_release_sent = true; - return 0; -} - -/* override, requires '-Wl,--wrap=iu_tx_common_id' */ -int __real_ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *ue_ctx, const char *imsi); -int __wrap_ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *ue_ctx, const char *imsi) +/* override, requires '-Wl,--wrap=call_leg_ensure_ci' */ +int __real_call_leg_ensure_ci(struct call_leg *cl, enum rtp_direction dir, uint32_t call_id, struct gsm_trans *for_trans); +int __wrap_call_leg_ensure_ci(struct call_leg *cl, enum rtp_direction dir, uint32_t call_id, struct gsm_trans *for_trans) { - btw("Iu Common ID --%s--> MS (IMSI=%s)", osmo_rat_type_name(OSMO_RAT_UTRAN_IU), imsi); + log("MS <--Call Assignment-- MSC: callref=0x%x", call_id); return 0; } -/* override, requires '-Wl,--wrap=a_iface_tx_dtap' */ -int __real_a_iface_tx_dtap(struct msgb *msg); -int __wrap_a_iface_tx_dtap(struct msgb *msg) -{ - return _validate_dtap(msg, OSMO_RAT_GERAN_A); -} - -/* override, requires '-Wl,--wrap=a_iface_tx_clear_cmd' */ -int __real_a_iface_tx_clear_cmd(struct ran_conn *conn); -int __wrap_a_iface_tx_clear_cmd(struct ran_conn *conn) -{ - btw("BSSAP Clear --%s--> MS", osmo_rat_type_name(OSMO_RAT_GERAN_A)); - OSMO_ASSERT(bssap_clear_expected); - bssap_clear_expected = false; - bssap_clear_sent = true; - return 0; -} - -/* override, requires '-Wl,--wrap=msc_mgcp_try_call_assignment' */ -int __real_msc_mgcp_try_call_assignment(struct gsm_trans *trans); -int __wrap_msc_mgcp_try_call_assignment(struct gsm_trans *trans) -{ - log("MS <--Call Assignment-- MSC: subscr=%s callref=0x%x", - vlr_subscr_name(trans->vsub), trans->callref); - return 0; -} - -struct gsm_mncc *on_call_release_mncc_sends_to_cc_data = NULL; - -/* override, requires '-Wl,--wrap=msc_mgcp_call_release' */ -void __real_msc_mgcp_call_release(struct gsm_trans *trans); -void __wrap_msc_mgcp_call_release(struct gsm_trans *trans) -{ - log("MS <--Call Release-- MSC: subscr=%s callref=0x%x", - vlr_subscr_name(trans->vsub), trans->callref); - if (on_call_release_mncc_sends_to_cc_data) { - mncc_tx_to_cc(trans->net, on_call_release_mncc_sends_to_cc_data->msg_type, - on_call_release_mncc_sends_to_cc_data); - on_call_release_mncc_sends_to_cc_data = NULL; - } -} - static int fake_vlr_tx_lu_acc(void *msc_conn_ref, uint32_t send_tmsi) { - struct ran_conn *conn = msc_conn_ref; + struct msc_a *msc_a = msc_conn_ref; if (send_tmsi == GSM_RESERVED_TMSI) - btw("sending LU Accept for %s", vlr_subscr_name(conn->vsub)); + btw("sending LU Accept for %s", msc_a->c.fi->id); else btw("sending LU Accept for %s, with TMSI 0x%08x", - vlr_subscr_name(conn->vsub), send_tmsi); + msc_a->c.fi->id, send_tmsi); lu_result_sent |= RES_ACCEPT; return 0; } static int fake_vlr_tx_lu_rej(void *msc_conn_ref, enum gsm48_reject_value cause) { - struct ran_conn *conn = msc_conn_ref; - btw("sending LU Reject for %s, cause %u", vlr_subscr_name(conn->vsub), cause); + struct msc_a *msc_a = msc_conn_ref; + btw("sending LU Reject for %s, cause %u", msc_a->c.fi->id, cause); lu_result_sent |= RES_REJECT; return 0; } -static int fake_vlr_tx_cm_serv_acc(void *msc_conn_ref) -{ - struct ran_conn *conn = msc_conn_ref; - btw("sending CM Service Accept for %s", vlr_subscr_name(conn->vsub)); - cm_service_result_sent |= RES_ACCEPT; - return 0; -} - -static int fake_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum gsm48_reject_value cause) +static int fake_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum osmo_cm_service_type cm_service_type, + enum gsm48_reject_value cause) { - struct ran_conn *conn = msc_conn_ref; - btw("sending CM Service Reject for %s, cause: %s", - vlr_subscr_name(conn->vsub), gsm48_reject_value_name(cause)); + struct msc_a *msc_a = msc_conn_ref; + btw("sending CM Service Reject (%s) for %s, cause: %s", + osmo_cm_service_type_name(cm_service_type), msc_a->c.fi->id, gsm48_reject_value_name(cause)); cm_service_result_sent |= RES_REJECT; return 0; } @@ -730,11 +791,11 @@ static int fake_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum gsm48_reject_value c static int fake_vlr_tx_auth_req(void *msc_conn_ref, struct vlr_auth_tuple *at, bool send_autn) { - struct ran_conn *conn = msc_conn_ref; + struct msc_a *msc_a = msc_conn_ref; char *hex; bool ok = true; btw("sending %s Auth Request for %s: tuple use_count=%d key_seq=%d auth_types=0x%x and...", - send_autn? "UMTS" : "GSM", vlr_subscr_name(conn->vsub), + send_autn? "UMTS" : "GSM", msc_a->c.fi->id, at->use_count, at->key_seq, at->vec.auth_types); hex = osmo_hexdump_nospc((void*)&at->vec.rand, sizeof(at->vec.rand)); @@ -774,104 +835,64 @@ static int fake_vlr_tx_auth_req(void *msc_conn_ref, struct vlr_auth_tuple *at, static int fake_vlr_tx_auth_rej(void *msc_conn_ref) { - struct ran_conn *conn = msc_conn_ref; - btw("sending Auth Reject for %s", vlr_subscr_name(conn->vsub)); + struct msc_a *msc_a = msc_conn_ref; + btw("sending Auth Reject for %s", msc_a->c.fi->id); return 0; } -/* override, requires '-Wl,--wrap=a_iface_tx_cipher_mode' */ -int __real_a_iface_tx_cipher_mode(const struct ran_conn *conn, - struct gsm0808_encrypt_info *ei, int include_imeisv); -int __wrap_a_iface_tx_cipher_mode(const struct ran_conn *conn, - struct gsm0808_encrypt_info *ei, int include_imeisv) +void ms_sends_ciphering_mode_complete(const char *inner_ran_msg) { - int i; - btw("sending Ciphering Mode Command for %s: include_imeisv=%d", - vlr_subscr_name(conn->vsub), include_imeisv); - for (i = 0; i < ei->perm_algo_len; i++) - btw("...perm algo: A5/%u", ei->perm_algo[i] - 1); - OSMO_ASSERT(ei->key_len <= sizeof(ei->key)); - btw("...key: %s", osmo_hexdump_nospc(ei->key, ei->key_len)); - cipher_mode_cmd_sent = true; - cipher_mode_cmd_sent_with_imeisv = include_imeisv; + struct ran_msg ran_dec; - if (!cipher_mode_expect_kc - || strcmp(cipher_mode_expect_kc, osmo_hexdump_nospc(ei->key, ei->key_len))) { - log("FAILURE: expected kc=%s", cipher_mode_expect_kc ? : "NULL"); - OSMO_ASSERT(false); - } - return 0; -} + msc_a_get(msub_msc_a(g_msub), __func__); -/* override, requires '-Wl,--wrap=ranap_iu_tx_sec_mode_cmd' */ -int __real_ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec, - int send_ck, int new_key); -int __wrap_ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec, - int send_ck, int new_key) -{ - btw("sending SecurityModeControl for UE ctx %u send_ck=%d new_key=%d", - uectx->conn_id, send_ck, new_key); - btw("...ik=%s", osmo_hexdump_nospc(vec->ik, sizeof(vec->ik))); - if (send_ck) - btw("...ck=%s", osmo_hexdump_nospc(vec->ck, sizeof(vec->ck))); - security_mode_ctrl_sent = true; - if (!security_mode_expect_ik - || strcmp(security_mode_expect_ik, osmo_hexdump_nospc(vec->ik, sizeof(vec->ik)))) { - log("FAILURE: expected ik=%s", security_mode_expect_ik ? : "NULL"); - OSMO_ASSERT(false); - } - if (((!!send_ck) != (!!security_mode_expect_ck)) - || (security_mode_expect_ck - && strcmp(security_mode_expect_ck, osmo_hexdump_nospc(vec->ck, sizeof(vec->ck))))) { - log("FAILURE: expected ck=%s", security_mode_expect_ck ? : "NULL"); - OSMO_ASSERT(false); + ran_dec = (struct ran_msg){ + .msg_type = RAN_MSG_CIPHER_MODE_COMPLETE, + }; + fake_msc_a_ran_dec(&ran_dec); + + if (inner_ran_msg) { + struct msgb *msg = msgb_from_hex("cipher_mode_complete_ran", 1024, inner_ran_msg); + msg->l1h = msg->l2h = msg->l3h = msg->data; + ran_dec = (struct ran_msg){ + .msg_type = RAN_MSG_DTAP, + .dtap = msg, + }; + patch_l3_seq_nr(msg); + fake_msc_a_ran_dec(&ran_dec); + msgb_free(msg); } - return 0; -} -extern int msc_vlr_set_ciph_mode(void *msc_conn_ref, bool umts_aka, bool retrieve_imeisv); + msc_a_put(msub_msc_a(g_msub), __func__); -static int fake_vlr_tx_ciph_mode_cmd(void *msc_conn_ref, bool umts_aka, bool retrieve_imeisv) -{ - int rc; -#ifndef BUILD_IU - /* If we built without support for IU, fake the IU part here. The root cause is that we don't - * have differing sets of expected outputs for --enable-iu and --disable-iu. */ - struct ran_conn *conn = msc_conn_ref; - if (conn->via_ran == OSMO_RAT_UTRAN_IU) { - DEBUGP(DMM, "-> SECURITY MODE CONTROL %s\n", vlr_subscr_name(conn->vsub)); - rc = __wrap_ranap_iu_tx_sec_mode_cmd(conn->iu.ue_ctx, &conn->vsub->last_tuple->vec, - 0, 1); - } else -#endif - rc = msc_vlr_set_ciph_mode(msc_conn_ref, umts_aka, retrieve_imeisv); - if (rc) - btw("ERROR sending ciphering mode command: rc=%d", rc); - return rc; + if (!conn_exists(g_msub)) + g_msub = NULL; } void ms_sends_security_mode_complete() { - OSMO_ASSERT(g_conn); - OSMO_ASSERT(g_conn->via_ran == OSMO_RAT_UTRAN_IU); - OSMO_ASSERT(g_conn->iu.ue_ctx); - ran_conn_rx_sec_mode_compl(g_conn); -} + struct ran_msg ran_dec; -void bss_sends_clear_complete() -{ - btw("BSS sends BSSMAP Clear Complete"); - OSMO_ASSERT(g_conn); - OSMO_ASSERT(g_conn->via_ran == OSMO_RAT_GERAN_A); - ran_conn_rx_bssmap_clear_complete(g_conn); + ran_dec = (struct ran_msg){ + .msg_type = RAN_MSG_CIPHER_MODE_COMPLETE, + }; + fake_msc_a_ran_dec(&ran_dec); + + if (!conn_exists(g_msub)) + g_msub = NULL; } -void rnc_sends_release_complete() +void ran_sends_clear_complete() { - btw("RNC sends Iu Release Complete"); - OSMO_ASSERT(g_conn); - OSMO_ASSERT(g_conn->via_ran == OSMO_RAT_UTRAN_IU); - ran_conn_rx_iu_release_complete(g_conn); + struct ran_msg ran_dec; + + ran_dec = (struct ran_msg){ + .msg_type = RAN_MSG_CLEAR_COMPLETE, + }; + fake_msc_a_ran_dec(&ran_dec); + + if (!conn_exists(g_msub)) + g_msub = NULL; } const struct timeval fake_time_start_time = { 123, 456 }; @@ -895,25 +916,29 @@ static void check_talloc(void *msgb_ctx, void *msc_vlr_tests_ctx) /* Verifying that the msgb context is empty */ talloc_report_full(msgb_ctx, stderr); /* Expecting these to stick around in msc_vlr_tests_ctx: - * talloc_total_blocks(tall_bsc_ctx) == 13 - * full talloc report on 'msc_vlr_tests_ctx' (total 4638 bytes in 13 blocks) - * struct osmo_gsup_client contains 256 bytes in 1 blocks (ref 0) 0x61300000dd20 - * struct gsm_network contains 2983 bytes in 5 blocks (ref 0) 0x61400000fea0 - * struct vlr_instance contains 320 bytes in 2 blocks (ref 0) 0x61300000dee0 - * struct ipaccess_unit contains 64 bytes in 1 blocks (ref 0) 0x60e0000244c0 - * no_gsup_server contains 15 bytes in 1 blocks (ref 0) 0x60b00000af40 - * rate_ctr.c:234 contains 2352 bytes in 1 blocks (ref 0) 0x61e00000f0e0 - * logging contains 1399 bytes in 5 blocks (ref 0) 0x60b00000aff0 - * struct log_target contains 238 bytes in 2 blocks (ref 0) 0x61200000bf20 - * struct log_category contains 70 bytes in 1 blocks (ref 0) 0x60f00000efb0 - * struct log_info contains 1160 bytes in 2 blocks (ref 0) 0x60d00000cfd0 - * struct log_info_cat contains 1120 bytes in 1 blocks (ref 0) 0x61a00001f2e0 - * msgb contains 0 bytes in 1 blocks (ref 0) 0x60800000bf80 - * (That's 13 counting the root ctx) + * full talloc report on 'msgb' (total 0 bytes in 1 blocks) + * talloc_total_blocks(tall_bsc_ctx) == 17 + * full talloc report on 'msc_vlr_tests_ctx' (total 6336 bytes in 17 blocks) + * struct osmo_gsup_client contains 256 bytes in 1 blocks (ref 0) 0x613000000260 + * struct gsm_network contains 4647 bytes in 9 blocks (ref 0) 0x6190000000e0 + * struct mgcp_client contains 688 bytes in 1 blocks (ref 0) 0x6180000000e0 + * struct sccp_ran_inst contains 152 bytes in 1 blocks (ref 0) 0x611000000460 + * struct sccp_ran_inst contains 152 bytes in 1 blocks (ref 0) 0x611000000320 + * struct gsup_client_mux contains 200 bytes in 2 blocks (ref 0) 0x6110000001e0 + * struct ipaccess_unit contains 64 bytes in 1 blocks (ref 0) 0x60e000023180 + * struct vlr_instance contains 248 bytes in 1 blocks (ref 0) 0x6130000000a0 + * no_gsup_server contains 15 bytes in 1 blocks (ref 0) 0x60b000000150 + * ../../../src/libosmocore/src/rate_ctr.c:234 contains 2352 bytes in 1 blocks (ref 0) 0x61e0000000e0 + * logging contains 1433 bytes in 5 blocks (ref 0) 0x60b0000000a0 + * struct log_target contains 240 bytes in 2 blocks (ref 0) 0x6120000000a0 + * struct log_category contains 72 bytes in 1 blocks (ref 0) 0x60f0000000a0 + * struct log_info contains 1192 bytes in 2 blocks (ref 0) 0x60d0000000a0 + * struct log_info_cat contains 1152 bytes in 1 blocks (ref 0) 0x61a0000000e0 + * msgb contains 0 bytes in 1 blocks (ref 0) 0x608000000100 */ fprintf(stderr, "talloc_total_blocks(tall_bsc_ctx) == %zu\n", talloc_total_blocks(msc_vlr_tests_ctx)); - if (talloc_total_blocks(msc_vlr_tests_ctx) != 13) + if (talloc_total_blocks(msc_vlr_tests_ctx) != 17) talloc_report_full(msc_vlr_tests_ctx, stderr); fprintf(stderr, "\n"); } @@ -1002,17 +1027,38 @@ struct gsm_network *test_net(void *ctx) net->gsup_server_port = 0; OSMO_ASSERT(msc_vlr_alloc(net) == 0); - OSMO_ASSERT(msc_vlr_start(net) == 0); OSMO_ASSERT(net->vlr); - OSMO_ASSERT(net->vlr->gsup_client); + OSMO_ASSERT(msc_gsup_client_start(net) == 0); + OSMO_ASSERT(net->gcm); + OSMO_ASSERT(msc_vlr_start(net) == 0); net->vlr->ops.tx_lu_acc = fake_vlr_tx_lu_acc; net->vlr->ops.tx_lu_rej = fake_vlr_tx_lu_rej; - net->vlr->ops.tx_cm_serv_acc = fake_vlr_tx_cm_serv_acc; + net->vlr->ops.tx_cm_serv_acc = msc_vlr_tx_cm_serv_acc; net->vlr->ops.tx_cm_serv_rej = fake_vlr_tx_cm_serv_rej; net->vlr->ops.tx_auth_req = fake_vlr_tx_auth_req; net->vlr->ops.tx_auth_rej = fake_vlr_tx_auth_rej; - net->vlr->ops.set_ciph_mode = fake_vlr_tx_ciph_mode_cmd; + net->vlr->ops.set_ciph_mode = msc_a_vlr_set_cipher_mode; + + /* Allocate fake SCCP Ran Instances */ + net->a.sri = talloc_zero(net, struct sccp_ran_inst); + *net->a.sri = (struct sccp_ran_inst){ + .ran = &test_ran_infra[OSMO_RAT_GERAN_A], + }; + INIT_LLIST_HEAD(&net->a.sri->ran_peers); + INIT_LLIST_HEAD(&net->a.sri->ran_conns); + + net->iu.sri = talloc_zero(net, struct sccp_ran_inst); + *net->iu.sri = (struct sccp_ran_inst){ + .ran = &test_ran_infra[OSMO_RAT_UTRAN_IU], + }; + INIT_LLIST_HEAD(&net->iu.sri->ran_peers); + INIT_LLIST_HEAD(&net->iu.sri->ran_conns); + + net->mgw.tdefs = g_mgw_tdefs; + mgcp_client_conf_init(&net->mgw.conf); + net->mgw.tdefs = g_mgw_tdefs; + net->mgw.client = mgcp_client_init(net, &net->mgw.conf); return net; } @@ -1046,8 +1092,11 @@ int main(int argc, char **argv) net = test_net(msc_vlr_tests_ctx); osmo_fsm_log_addr(false); + osmo_fsm_log_timeouts(cmdline_opts.verbose); + + call_leg_init(net); - ran_conn_init(); + OSMO_ASSERT(osmo_fsm_register(&dummy_msc_i_fsm) == 0); clear_vlr(); |