| /* Osmocom MSC+VLR end-to-end tests */ |
| |
| /* (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 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/>. |
| * |
| */ |
| |
| #pragma once |
| |
| #include <stdbool.h> |
| #include <stdio.h> |
| |
| #include <osmocom/msc/gsm_data.h> |
| #include <osmocom/msc/vlr.h> |
| #include <osmocom/msc/msub.h> |
| #include <osmocom/msc/msc_a.h> |
| #include <osmocom/msc/mncc.h> |
| |
| #define A5_0 (1 << 0) |
| #define A5_0_3 ((1 << 0) | (1 << 3)) |
| |
| extern bool _log_lines; |
| #define _log(fmt, args...) do { \ |
| if (_log_lines) \ |
| fprintf(stderr, " %4d:%s: " fmt "\n", \ |
| __LINE__, __FILE__, ## args ); \ |
| else \ |
| fprintf(stderr, fmt "\n", ## args ); \ |
| } while (false) |
| |
| /* btw means "by the way", the test tells the log what's happening. |
| * BTW() marks a larger section, btw() is the usual logging. */ |
| #define BTW(fmt, args...) _log("\n\n- " fmt, ## args ) |
| #define btw(fmt, args...) _log("- " fmt, ## args ) |
| #define log(fmt, args...) _log(" " fmt, ## args ) |
| |
| #define comment_start() fprintf(stderr, "===== %s\n", __func__); |
| #define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__); |
| |
| extern struct msub *g_msub; |
| extern struct gsm_network *net; |
| extern void *msgb_ctx; |
| |
| extern enum osmo_rat_type rx_from_ran; |
| |
| extern const char *gsup_tx_expected; |
| extern bool gsup_tx_confirmed; |
| |
| extern struct msgb *dtap_tx_expected; |
| extern bool dtap_tx_confirmed; |
| |
| enum result_sent { |
| RES_NONE = 0, |
| RES_ACCEPT = 1, |
| RES_REJECT = 2, |
| }; |
| extern enum result_sent lu_result_sent; |
| extern enum result_sent cm_service_result_sent; |
| |
| extern bool auth_request_sent; |
| extern const char *auth_request_expect_rand; |
| extern const char *auth_request_expect_autn; |
| |
| extern bool cipher_mode_cmd_sent; |
| extern bool cipher_mode_cmd_sent_with_imeisv; |
| extern const char *cipher_mode_expect_kc; |
| |
| extern bool security_mode_ctrl_sent; |
| extern const char *security_mode_expect_ck; |
| extern const char *security_mode_expect_ik; |
| |
| static inline void expect_cipher_mode_cmd(const char *kc) |
| { |
| cipher_mode_cmd_sent = false; |
| cipher_mode_expect_kc = kc; |
| /* make sure we don't mix up the two */ |
| security_mode_ctrl_sent = false; |
| } |
| |
| static inline void expect_security_mode_ctrl(const char *ck, const char *ik) |
| { |
| security_mode_ctrl_sent = false; |
| security_mode_expect_ck = ck; |
| security_mode_expect_ik = ik; |
| /* make sure we don't mix up the two */ |
| cipher_mode_cmd_sent = false; |
| } |
| |
| extern bool paging_sent; |
| |
| extern bool iu_release_expected; |
| extern bool iu_release_sent; |
| extern bool bssap_clear_expected; |
| extern bool bssap_clear_sent; |
| |
| extern uint32_t cc_to_mncc_tx_expected_msg_type; |
| extern const char *cc_to_mncc_tx_expected_imsi; |
| extern bool cc_to_mncc_tx_confirmed; |
| extern uint32_t cc_to_mncc_tx_got_callref; |
| |
| extern struct gsm_mncc *on_call_release_mncc_sends_to_cc_data; |
| |
| static inline void expect_iu_release() |
| { |
| iu_release_expected = true; |
| iu_release_sent = false; |
| } |
| |
| static inline void expect_bssap_clear() |
| { |
| bssap_clear_expected = true; |
| bssap_clear_sent = false; |
| } |
| |
| static inline void expect_release_clear(enum osmo_rat_type via_ran) |
| { |
| switch (via_ran) { |
| case OSMO_RAT_GERAN_A: |
| expect_bssap_clear(); |
| return; |
| case OSMO_RAT_UTRAN_IU: |
| expect_iu_release(); |
| return; |
| default: |
| OSMO_ASSERT(false); |
| break; |
| } |
| } |
| |
| struct msc_vlr_test_cmdline_opts { |
| bool verbose; |
| int run_test_nr; |
| }; |
| |
| typedef void (* msc_vlr_test_func_t )(void); |
| extern msc_vlr_test_func_t msc_vlr_tests[]; |
| |
| struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex); |
| |
| void clear_vlr(); |
| bool conn_exists(const struct msub *msub); |
| void conn_conclude_cm_service_req(struct msub *msub, const char *cm_service_use); |
| |
| void dtap_expect_tx(const char *hex); |
| void dtap_expect_tx_ussd(char *ussd_text); |
| void paging_expect_imsi(const char *imsi); |
| void paging_expect_tmsi(uint32_t tmsi); |
| |
| void ms_sends_msg(const char *hex); |
| void ms_sends_classmark_update(const struct osmo_gsm48_classmark *classmark); |
| void ms_sends_ciphering_mode_complete(const char *inner_nas_msg); |
| void ms_sends_security_mode_complete(); |
| void gsup_rx(const char *rx_hex, const char *expect_tx_hex); |
| void send_sms(struct vlr_subscr *receiver, |
| struct vlr_subscr *sender, |
| char *str); |
| |
| void ran_sends_clear_complete(); |
| |
| void thwart_rx_non_initial_requests(); |
| |
| #define EXPECT_ACCEPTED(expect_accepted) do { \ |
| if (g_msub) \ |
| OSMO_ASSERT(conn_exists(g_msub)); \ |
| bool accepted = msc_a_is_accepted(msub_msc_a(g_msub)); \ |
| fprintf(stderr, "msc_a_is_accepted() == %s\n", \ |
| accepted ? "true" : "false"); \ |
| OSMO_ASSERT(accepted == expect_accepted); \ |
| } while (false) |
| |
| #define VAL_ASSERT(desc, val, expect_op, fmt) \ |
| do { \ |
| log(desc " == " fmt, (val)); \ |
| OSMO_ASSERT((val) expect_op); \ |
| } while (0) |
| |
| #define VERBOSE_ASSERT(val, expect_op, fmt) VAL_ASSERT(#val, val, expect_op, fmt) |
| |
| #define EXPECT_CONN_COUNT(N) VERBOSE_ASSERT(llist_count(&msub_list), == N, "%d") |
| |
| #define gsup_expect_tx(hex) do \ |
| { \ |
| if (gsup_tx_expected) { \ |
| log("Previous expected GSUP tx was not confirmed!"); \ |
| OSMO_ASSERT(!gsup_tx_expected); \ |
| } \ |
| if (!hex) \ |
| break; \ |
| gsup_tx_expected = hex; \ |
| gsup_tx_confirmed = false; \ |
| } while (0) |
| |
| #define cc_to_mncc_expect_tx(imsi, msg_type) do \ |
| { \ |
| if (cc_to_mncc_tx_expected_msg_type) { \ |
| log("Previous expected MNCC tx was not confirmed!"); \ |
| OSMO_ASSERT(!cc_to_mncc_tx_expected_msg_type); \ |
| } \ |
| cc_to_mncc_tx_expected_imsi = imsi; \ |
| cc_to_mncc_tx_expected_msg_type = msg_type; \ |
| cc_to_mncc_tx_confirmed = false; \ |
| } while (0) |
| |
| void fake_time_start(); |
| |
| /* as macro to get the test file's source line number */ |
| #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); \ |
| btw("Total time passed: %d.%06d s", \ |
| (int)diff.tv_sec, (int)diff.tv_usec); \ |
| osmo_timers_prepare(); \ |
| osmo_timers_update(); \ |
| } while (0) |
| |
| extern const struct timeval fake_time_start_time; |
| |
| #define ASSERT_RELEASE_CLEAR(via_ran) \ |
| switch (via_ran) { \ |
| case OSMO_RAT_GERAN_A: \ |
| VERBOSE_ASSERT(bssap_clear_sent, == true, "%d"); \ |
| break; \ |
| case OSMO_RAT_UTRAN_IU: \ |
| VERBOSE_ASSERT(iu_release_sent, == true, "%d"); \ |
| break; \ |
| default: \ |
| OSMO_ASSERT(false); \ |
| break; \ |
| } |
| |
| #define HLR_TO_VLR "0a0101" |
| #define VLR_TO_HLR "0a0101" |
| #define EUSE_TO_MSC_USSD "0a0103" |
| #define MSC_USSD_TO_EUSE "0a0103" |