blob: 062d8a35b63c93a5d88abe02205275762eb07f95 [file] [log] [blame]
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001/* Osmocom MSC+VLR end-to-end tests */
2
3/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 *
5 * All Rights Reserved
6 *
7 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <getopt.h>
25#include <stdlib.h>
26
27#include <osmocom/core/logging.h>
28#include <osmocom/core/utils.h>
29#include <osmocom/core/msgb.h>
30#include <osmocom/core/application.h>
31#include <osmocom/gsm/protocol/gsm_04_11.h>
32#include <osmocom/gsm/gsup.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010033#include <osmocom/msc/gsup_client_mux.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020034#include <osmocom/msc/gsm_04_11.h>
35#include <osmocom/msc/debug.h>
Max43b01b02017-09-15 11:22:30 +020036#include <osmocom/msc/gsm_04_08.h>
Neels Hofmeyra99b4272017-11-21 17:13:23 +010037#include <osmocom/msc/transaction.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010038#include <osmocom/msc/ran_msg.h>
39#include <osmocom/msc/msc_a.h>
40#include <osmocom/msc/msc_i.h>
41#include <osmocom/msc/msc_t.h>
42#include <osmocom/msc/call_leg.h>
43#include <osmocom/msc/rtp_stream.h>
Neels Hofmeyr62bfa372022-10-31 18:51:07 +010044#include <osmocom/msc/codec_mapping.h>
Neels Hofmeyr6a29d322017-01-25 15:04:16 +010045
46#include "msc_vlr_tests.h"
47
Neels Hofmeyrc01e9092018-03-22 15:56:49 +010048void *msc_vlr_tests_ctx = NULL;
Neels Hofmeyrdbb3c722021-02-07 23:53:07 +010049void *msgb_ctx = NULL;
Neels Hofmeyrc01e9092018-03-22 15:56:49 +010050
Neels Hofmeyr6a29d322017-01-25 15:04:16 +010051bool _log_lines = false;
52
53struct gsm_network *net = NULL;
54
Neels Hofmeyr6a29d322017-01-25 15:04:16 +010055const char *gsup_tx_expected = NULL;
56bool gsup_tx_confirmed;
57
58struct msgb *dtap_tx_expected = NULL;
59bool dtap_tx_confirmed;
60
61enum result_sent lu_result_sent;
62enum result_sent cm_service_result_sent;
63bool auth_request_sent;
64const char *auth_request_expect_rand;
65const char *auth_request_expect_autn;
66bool cipher_mode_cmd_sent;
67bool cipher_mode_cmd_sent_with_imeisv;
Neels Hofmeyrdbabfd32018-03-10 02:06:47 +010068const char *cipher_mode_expect_kc;
69bool security_mode_ctrl_sent;
70const char *security_mode_expect_ck;
71const char *security_mode_expect_ik;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +010072
Philipp Maierfbf66102017-04-09 12:32:51 +020073bool iu_release_expected = false;
74bool iu_release_sent = false;
75bool bssap_clear_expected = false;
76bool bssap_clear_sent = false;
77
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +020078bool bssap_assignment_expected = false;
79bool bssap_assignment_sent = false;
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +010080struct gsm0808_channel_type bssap_assignment_command_last_channel_type;
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +020081bool iu_rab_assignment_expected = false;
82bool iu_rab_assignment_sent = false;
83
Neels Hofmeyra99b4272017-11-21 17:13:23 +010084uint32_t cc_to_mncc_tx_expected_msg_type = 0;
85const char *cc_to_mncc_tx_expected_imsi = NULL;
86bool cc_to_mncc_tx_confirmed = false;
87uint32_t cc_to_mncc_tx_got_callref = 0;
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +010088char cc_to_mncc_tx_last_sdp[1024] = {};
Neels Hofmeyra99b4272017-11-21 17:13:23 +010089
Neels Hofmeyr81938fd2022-01-14 03:39:58 +010090bool expecting_crcx[2] = {};
91bool got_crcx[2] = {};
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +020092
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010093extern int ran_dec_dtap_undup_pdisc_ctr_bin(uint8_t pdisc);
Harald Weltec2007852018-02-03 21:08:26 +010094
95/* static state variables for the L3 send sequence numbers */
96static uint8_t n_sd[4];
97
98/* patch a correct send sequence number into the given message */
99static void patch_l3_seq_nr(struct msgb *msg)
100{
101 struct gsm48_hdr *gh = msgb_l3(msg);
102 uint8_t pdisc = gsm48_hdr_pdisc(gh);
103 uint8_t *msg_type_oct = &msg->l3h[1];
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100104 int bin = ran_dec_dtap_undup_pdisc_ctr_bin(pdisc);
Harald Weltec2007852018-02-03 21:08:26 +0100105
106 if (bin >= 0 && bin < ARRAY_SIZE(n_sd)) {
107 /* patch in n_sd into the msg_type octet */
108 *msg_type_oct = (*msg_type_oct & 0x3f) | ((n_sd[bin] & 0x3) << 6);
109 //fprintf(stderr, "pdisc=0x%02x bin=%d, patched n_sd=%u\n\n", pdisc, bin, n_sd[bin] & 3);
110 /* increment N(SD) */
111 n_sd[bin] = (n_sd[bin] + 1) % 4;
112 } else {
113 //fprintf(stderr, "pdisc=0x%02x NO SEQ\n\n", pdisc);
114 }
115}
116
117/* reset L3 sequence numbers (e.g. new RR connection) */
118static void reset_l3_seq_nr()
119{
120 memset(n_sd, 0, sizeof(n_sd));
121}
122
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100123struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex)
124{
Neels Hofmeyr3117b702018-09-13 03:23:07 +0200125 struct msgb *msg = msgb_alloc_headroom(size, 4, label);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100126 unsigned char *rc;
Neels Hofmeyr3117b702018-09-13 03:23:07 +0200127 msg->l2h = msg->data;
128 rc = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100129 OSMO_ASSERT(rc == msg->l2h);
130 return msg;
131}
132
Maxd8d1a9e2018-02-06 15:50:20 +0100133static const char *gh_type_name(struct gsm48_hdr *gh)
Neels Hofmeyr78ada642017-03-10 02:15:20 +0100134{
135 return gsm48_pdisc_msgtype_name(gsm48_hdr_pdisc(gh),
136 gsm48_hdr_msg_type(gh));
137}
138
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100139void gsup_rx(const char *rx_hex, const char *expect_tx_hex)
140{
141 int rc;
142 struct msgb *msg;
143 const char *label;
144
145 gsup_expect_tx(expect_tx_hex);
146
147 msg = msgb_from_hex("gsup", 1024, rx_hex);
148 label = osmo_gsup_message_type_name(msg->l2h[0]);
149 fprintf(stderr, "<-- GSUP rx %s: %s\n", label,
150 osmo_hexdump_nospc(msgb_l2(msg), msgb_l2len(msg)));
Neels Hofmeyr834f94a2017-09-28 03:07:16 +0200151 /* GSUP read cb takes ownership of msgb */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100152 rc = gsup_client_mux_rx(net->gcm->gsup_client, msg);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100153 fprintf(stderr, "<-- GSUP rx %s: vlr_gsupc_read_cb() returns %d\n",
154 label, rc);
155 if (expect_tx_hex)
156 OSMO_ASSERT(gsup_tx_confirmed);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100157}
158
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100159bool conn_exists(const struct msub *msub)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100160{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100161 struct msub *i;
Maxba8a0072018-10-25 17:58:43 +0200162
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100163 if (!msub)
Maxba8a0072018-10-25 17:58:43 +0200164 return false;
165
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100166 llist_for_each_entry(i, &msub_list, entry) {
167 if (i == msub)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100168 return true;
169 }
Maxba8a0072018-10-25 17:58:43 +0200170
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100171 btw("msub gone");
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100172 return false;
173}
174
Vadim Yanitskiy27605852018-06-15 23:57:30 +0700175/* Simplified version of the cm_service_request_concludes() */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100176void conn_conclude_cm_service_req(struct msub *msub, const char *cm_service_use)
Vadim Yanitskiy27605852018-06-15 23:57:30 +0700177{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100178 int32_t count;
179 struct msc_a *msc_a = msub_msc_a(msub);
Vadim Yanitskiy27605852018-06-15 23:57:30 +0700180 btw("Concluding CM Service Request");
181
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100182 OSMO_ASSERT(conn_exists(msub));
183 count = osmo_use_count_by(&msc_a->use_count, cm_service_use);
184 OSMO_ASSERT(count > 0);
Vadim Yanitskiy27605852018-06-15 23:57:30 +0700185
Vadim Yanitskiyd14422a2019-07-09 00:37:49 +0700186 OSMO_ASSERT(osmo_use_count_get_put(&msc_a->use_count, cm_service_use, -count) == 0);
Vadim Yanitskiy27605852018-06-15 23:57:30 +0700187
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100188 ASSERT_RELEASE_CLEAR(msc_a->c.ran->type);
189}
190
191void dummy_msc_i_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
192{
193}
194
195static const struct osmo_fsm_state dummy_msc_i_states[] = {
196 {
197 .name = "0",
198 .in_event_mask = 0xffffffff,
199 .action = dummy_msc_i_action,
200 },
201};
202
203struct osmo_fsm dummy_msc_i_fsm = {
204 .name = "dummy_msc_i",
205 .states = dummy_msc_i_states,
206 .num_states = ARRAY_SIZE(dummy_msc_i_states),
207 .log_subsys = DMSC,
208 .event_names = msc_i_fsm_event_names,
209};
210
211struct msc_i *dummy_msc_i_alloc(struct msub *msub, struct ran_infra *ran)
212{
213 return msub_role_alloc(g_msub, MSC_ROLE_I, &dummy_msc_i_fsm, struct msc_i, ran);
Vadim Yanitskiy27605852018-06-15 23:57:30 +0700214}
215
Neels Hofmeyr7814a832018-12-26 00:40:18 +0100216enum osmo_rat_type rx_from_ran = OSMO_RAT_GERAN_A;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100217
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100218struct msub *g_msub = NULL;
Harald Welte977b5482019-02-18 12:23:43 +0100219
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100220void dtap_expect_tx(const char *hex)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100221{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100222 /* Has the previously expected dtap been received? */
223 OSMO_ASSERT(!dtap_tx_expected);
224 if (!hex)
225 return;
226 dtap_tx_expected = msgb_from_hex("dtap_tx_expected", 1024, hex);
227 /* Mask the sequence number out */
228 if (msgb_length(dtap_tx_expected) >= 2)
229 dtap_tx_expected->data[1] &= 0x3f;
230 dtap_tx_confirmed = false;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100231}
232
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100233static int _validate_dtap(struct msgb *msg, enum osmo_rat_type to_ran)
234{
235 struct gsm48_hdr *gh = (void*)msg->data;
236 uint8_t pdisc = gsm48_hdr_pdisc(gh);
237 uint8_t msgt = gsm48_hdr_msg_type(gh);
238
239 btw("DTAP --%s--> MS: %s: %s",
240 osmo_rat_type_name(to_ran), gh_type_name((void*)msg->data),
241 osmo_hexdump_nospc(msg->data, msg->len));
242
243 if (pdisc == GSM48_PDISC_MM
244 && msgt == GSM48_MT_MM_CM_SERV_ACC) {
245 cm_service_result_sent |= RES_ACCEPT;
246 talloc_free(msg);
247 return 0;
248 }
249
250 if (pdisc == GSM48_PDISC_MM
251 && msgt == GSM48_MT_MM_CM_SERV_REJ) {
252 cm_service_result_sent |= RES_REJECT;
253 talloc_free(msg);
254 return 0;
255 }
256
257 OSMO_ASSERT(dtap_tx_expected);
258
259 /* Mask the sequence number out before comparing */
260 msg->data[1] &= 0x3f;
Neels Hofmeyre0f906c2019-10-21 06:00:35 +0200261 if (!msgb_eq_data_print(msg, dtap_tx_expected->data, dtap_tx_expected->len)) {
262 btw("Expected %s", osmo_hexdump(dtap_tx_expected->data, dtap_tx_expected->len));
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100263 abort();
Neels Hofmeyre0f906c2019-10-21 06:00:35 +0200264 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100265
266 btw("DTAP matches expected message");
267
268 talloc_free(msg);
269 dtap_tx_confirmed = true;
270 talloc_free(dtap_tx_expected);
271 dtap_tx_expected = NULL;
272
273 return 0;
274}
275
276static void bssap_validate_clear_cmd()
277{
278 OSMO_ASSERT(bssap_clear_expected);
279 bssap_clear_expected = false;
280 bssap_clear_sent = true;
281}
282
283static void iucs_validate_clear_cmd()
284{
285 OSMO_ASSERT(iu_release_expected);
286 iu_release_expected = false;
287 iu_release_sent = true;
288}
289
290static int bssap_validate_cipher_mode_cmd(const struct ran_cipher_mode_command *cmd)
291{
292 int i;
293 const char *got_key;
294 cipher_mode_cmd_sent = true;
295 cipher_mode_cmd_sent_with_imeisv = cmd->geran.retrieve_imeisv;
296 btw("sending Ciphering Mode Command: retrieve_imeisv=%d", cipher_mode_cmd_sent_with_imeisv);
297 for (i = 0; i < 7; i++) {
298 if (!(cmd->geran.a5_encryption_mask & (1 << i)))
299 continue;
300 btw("...perm algo: A5/%d", i);
301 }
302 got_key = osmo_hexdump_nospc(cmd->vec->kc, sizeof(cmd->vec->kc));
303 btw("...key: %s", got_key);
304
305 if (!cipher_mode_expect_kc
306 || strcmp(cipher_mode_expect_kc, got_key)) {
307 log("FAILURE: expected kc=%s", cipher_mode_expect_kc ? : "NULL");
308 OSMO_ASSERT(false);
309 }
310 return 0;
311}
312
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100313static void bssap_validate_assignment_cmd(const struct ran_assignment_command *assignment_command)
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200314{
315 OSMO_ASSERT(bssap_assignment_expected);
316 bssap_assignment_expected = false;
317 bssap_assignment_sent = true;
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100318 if (assignment_command->channel_type)
319 bssap_assignment_command_last_channel_type = *assignment_command->channel_type;
320 else
321 bssap_assignment_command_last_channel_type = (struct gsm0808_channel_type){};
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200322}
323
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100324static void iucs_validate_assignment_cmd(const struct ran_assignment_command *assignment_command)
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200325{
326 OSMO_ASSERT(iu_rab_assignment_expected);
327 iu_rab_assignment_expected = false;
328 iu_rab_assignment_sent = true;
329}
330
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100331static int iucs_validate_security_mode_ctrl(const struct ran_cipher_mode_command *cmd)
332{
333 const char *got_ik;
334 got_ik = osmo_hexdump_nospc(cmd->vec->ik, sizeof(cmd->vec->ik));
335 btw("sending SecurityModeControl: ik=%s", got_ik);
336 security_mode_ctrl_sent = true;
337 if (!security_mode_expect_ik
338 || strcmp(security_mode_expect_ik, got_ik)) {
339 log("FAILURE: expected ik=%s", security_mode_expect_ik ? : "NULL");
340 OSMO_ASSERT(false);
341 }
342 return 0;
343}
344
345struct msgb *dont_ran_encode(struct osmo_fsm_inst *caller_fi, const struct ran_msg *ran_enc_msg)
346{
347 struct msc_role_common *c = caller_fi->priv;
348 enum osmo_rat_type ran_type = c->ran->type;
349 const char *ran_name = osmo_rat_type_name(ran_type);
350 LOG_RAN_ENC(caller_fi, DMSC, LOGL_INFO, "%s on %s\n", ran_msg_type_name(ran_enc_msg->msg_type),
351 ran_name);
352
353 switch (ran_enc_msg->msg_type) {
354 case RAN_MSG_DTAP:
355 _validate_dtap(ran_enc_msg->dtap, ran_type);
356 break;
357 case RAN_MSG_CLEAR_COMMAND:
358 switch (ran_type) {
359 case OSMO_RAT_GERAN_A:
360 bssap_validate_clear_cmd();
361 break;
362 case OSMO_RAT_UTRAN_IU:
363 iucs_validate_clear_cmd();
364 break;
365 default:
366 OSMO_ASSERT(false);
367 }
368 break;
369 case RAN_MSG_CIPHER_MODE_COMMAND:
370 switch (ran_type) {
371 case OSMO_RAT_GERAN_A:
372 bssap_validate_cipher_mode_cmd(&ran_enc_msg->cipher_mode_command);
373 break;
374 case OSMO_RAT_UTRAN_IU:
375 iucs_validate_security_mode_ctrl(&ran_enc_msg->cipher_mode_command);
376 break;
377 default:
378 OSMO_ASSERT(false);
379 }
380 break;
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200381 case RAN_MSG_ASSIGNMENT_COMMAND:
382 switch (ran_type) {
383 case OSMO_RAT_GERAN_A:
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100384 bssap_validate_assignment_cmd(&ran_enc_msg->assignment_command);
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200385 break;
386 case OSMO_RAT_UTRAN_IU:
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100387 iucs_validate_assignment_cmd(&ran_enc_msg->assignment_command);
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200388 break;
389 default:
390 OSMO_ASSERT(false);
391 }
392 break;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100393 default:
394 break;
395 }
396
397 /* We're testing MSC and VLR interaction, not message encoding.
398 * Return whatever. The test msc_i instance is a dummy and drops these.
399 * But it must be msg_free()-able.
400 */
401 return msgb_alloc(1, "unused dummy msg");
402}
403
404struct ran_infra test_ran_infra[] = {
405 [OSMO_RAT_GERAN_A] = {
406 .type = OSMO_RAT_GERAN_A,
407 .an_proto = OSMO_GSUP_ACCESS_NETWORK_PROTOCOL_TS3G_48006,
408 .log_subsys = DBSSAP,
409 .tdefs = msc_tdefs_geran,
410 .ran_encode = dont_ran_encode,
411 },
412 [OSMO_RAT_UTRAN_IU] = {
413 .type = OSMO_RAT_UTRAN_IU,
414 .an_proto = OSMO_GSUP_ACCESS_NETWORK_PROTOCOL_TS3G_25413,
415 .log_subsys = DIUCS,
416 .tdefs = msc_tdefs_utran,
417 .ran_encode = dont_ran_encode,
Neels Hofmeyr1dc39612023-03-03 16:43:19 +0100418 .force_mgw_codecs_to_ran = {
419 .count = 1,
420 .codec = {
421 {
422 .payload_type = 96,
423 .subtype_name = "VND.3GPP.IUFP",
424 .rate = 16000,
425 },
426 },
427 },
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100428 },
429};
430
431static int fake_msc_a_ran_dec(const struct ran_msg *ran_dec_msg)
432{
433 struct msc_a_ran_dec_data d = {
434 .from_role = MSC_ROLE_I,
435 };
436 return msc_a_ran_decode_cb(g_msub->role[MSC_ROLE_A], &d, ran_dec_msg);
437}
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100438
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100439void rx_from_ms(struct msgb *msg, const struct gsm0808_speech_codec_list *codec_list_bss_supported)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100440{
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100441 struct gsm48_hdr *gh = msgb_l3(msg);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100442 struct ran_msg ran_dec_msg;
443 struct gsm0808_cell_id cell_id = {
444 .id_discr = CELL_IDENT_LAI_AND_LAC,
445 .id.lai_and_lac = {
446 .plmn = {
447 .mcc = 1,
448 .mnc = 2,
449 },
450 .lac = 23,
451 },
452 };
453 struct msc_a *msc_a;
Neels Hofmeyr78ada642017-03-10 02:15:20 +0100454
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100455 log("MSC <--%s-- MS: %s", osmo_rat_type_name(rx_from_ran), gh_type_name(gh));
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100456
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100457 if (!conn_exists(g_msub))
458 g_msub = NULL;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100459
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100460 if (!g_msub) {
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100461 log("new conn");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100462 g_msub = msub_alloc(net);
463 msc_a_alloc(g_msub, &test_ran_infra[rx_from_ran]);
464 dummy_msc_i_alloc(g_msub, &test_ran_infra[rx_from_ran]);
465
Harald Weltec2007852018-02-03 21:08:26 +0100466 reset_l3_seq_nr();
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100467 ran_dec_msg = (struct ran_msg){
468 .msg_type = RAN_MSG_COMPL_L3,
469 .compl_l3 = {
470 .cell_id = &cell_id,
471 .msg = msg,
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100472 .codec_list_bss_supported = codec_list_bss_supported,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100473 },
474 };
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100475 } else {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100476 ran_dec_msg = (struct ran_msg){
477 .msg_type = RAN_MSG_DTAP,
478 .dtap = msg,
479 };
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100480 }
481
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100482 msc_a = msub_msc_a(g_msub);
483 msc_a_get(msc_a, __func__);
484
485 patch_l3_seq_nr(msg);
486 fake_msc_a_ran_dec(&ran_dec_msg);
487
488 msc_a_put(msc_a, __func__);
489
490 if (!conn_exists(g_msub))
491 g_msub = NULL;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100492}
493
494void ms_sends_msg(const char *hex)
495{
496 struct msgb *msg;
497
498 msg = msgb_from_hex("ms_sends_msg", 1024, hex);
499 msg->l1h = msg->l2h = msg->l3h = msg->data;
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100500 rx_from_ms(msg, NULL);
501 msgb_free(msg);
502}
503
504void ms_sends_msgf(const char *fmt, ...)
505{
506 va_list ap;
507 char *hex;
508
509 va_start(ap, fmt);
510 hex = talloc_vasprintf(msc_vlr_tests_ctx, fmt, ap);
511 va_end(ap);
512
513 ms_sends_msg(hex);
514 talloc_free(hex);
515}
516
517void ms_sends_compl_l3(const char *hex, const struct gsm0808_speech_codec_list *codec_list_bss_supported)
518{
519 struct msgb *msg;
520
521 msg = msgb_from_hex("ms_sends_msg", 1024, hex);
522 msg->l1h = msg->l2h = msg->l3h = msg->data;
523 rx_from_ms(msg, codec_list_bss_supported);
Neels Hofmeyr3117b702018-09-13 03:23:07 +0200524 msgb_free(msg);
525}
526
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100527void ms_sends_classmark_update(const struct osmo_gsm48_classmark *classmark)
Neels Hofmeyr3117b702018-09-13 03:23:07 +0200528{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100529 struct ran_msg ran_dec = {
530 .msg_type = RAN_MSG_CLASSMARK_UPDATE,
531 .classmark_update = {
532 .classmark = classmark,
533 },
534 };
535 fake_msc_a_ran_dec(&ran_dec);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100536}
537
Maxd8d1a9e2018-02-06 15:50:20 +0100538static int ms_sends_msg_fake(uint8_t pdisc, uint8_t msg_type)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100539{
540 int rc;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100541 struct ran_msg ran_dec;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100542 struct msgb *msg;
543 struct gsm48_hdr *gh;
544
545 msg = msgb_alloc(1024, "ms_sends_msg_fake");
546 msg->l1h = msg->l2h = msg->l3h = msg->data;
547
548 gh = (struct gsm48_hdr*)msgb_put(msg, sizeof(*gh));
549 gh->proto_discr = pdisc;
550 gh->msg_type = msg_type;
551 /* some amount of data, whatever */
552 msgb_put(msg, 123);
553
Harald Weltec2007852018-02-03 21:08:26 +0100554 patch_l3_seq_nr(msg);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100555
556 ran_dec = (struct ran_msg){
557 .msg_type = RAN_MSG_DTAP,
558 .dtap = msg,
559 };
560 rc = fake_msc_a_ran_dec(&ran_dec);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100561
562 talloc_free(msg);
563 return rc;
564}
565
Max68171902018-02-06 17:55:19 +0100566static inline void ms_msg_log_err(uint8_t val, uint8_t msgtype)
567{
568 int rc = ms_sends_msg_fake(val, msgtype);
569 if (rc != -EACCES)
570 log("Unexpected return value %u != %u for %s/%s",
571 -rc, -EACCES, gsm48_pdisc_name(val), gsm48_cc_msg_name(msgtype));
572}
573
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100574void thwart_rx_non_initial_requests()
575{
576 log("requests shall be thwarted");
Max68171902018-02-06 17:55:19 +0100577
578 ms_msg_log_err(GSM48_PDISC_CC, GSM48_MT_CC_SETUP);
579 ms_msg_log_err(GSM48_PDISC_MM, 0x33); /* nonexistent */
580 ms_msg_log_err(GSM48_PDISC_RR, GSM48_MT_RR_SYSINFO_1);
581 ms_msg_log_err(GSM48_PDISC_SMS, GSM411_MT_CP_DATA);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100582}
583
584void send_sms(struct vlr_subscr *receiver,
585 struct vlr_subscr *sender,
586 char *str)
587{
Harald Welte39b55482018-04-09 19:19:33 +0200588 struct gsm_sms *sms = sms_from_text(receiver, sender->msisdn, 0, str);
Vadim Yanitskiy24e025e2018-11-22 15:42:39 +0700589 gsm411_send_sms(net, receiver, sms);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100590}
591
592unsigned char next_rand_byte = 0;
Max753c15d2017-12-21 14:50:44 +0100593/* override, requires '-Wl,--wrap=osmo_get_rand_id' */
594int __real_osmo_get_rand_id(uint8_t *buf, size_t num);
595int __wrap_osmo_get_rand_id(uint8_t *buf, size_t num)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100596{
Max753c15d2017-12-21 14:50:44 +0100597 size_t i;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100598 for (i = 0; i < num; i++)
599 buf[i] = next_rand_byte++;
600 return 1;
601}
602
603/* override, requires '-Wl,--wrap=gsm340_gen_scts' */
604void __real_gsm340_gen_scts(uint8_t *scts, time_t time);
605void __wrap_gsm340_gen_scts(uint8_t *scts, time_t time)
606{
Neels Hofmeyr05230ea2017-08-22 18:06:42 +0200607 /* Write fixed time bytes for deterministic test results */
608 osmo_hexparse("07101000000000", scts, 7);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100609}
610
611const char *paging_expecting_imsi = NULL;
612uint32_t paging_expecting_tmsi;
613bool paging_sent;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100614
615void paging_expect_imsi(const char *imsi)
616{
617 paging_expecting_imsi = imsi;
618 paging_expecting_tmsi = GSM_RESERVED_TMSI;
619}
620
621void paging_expect_tmsi(uint32_t tmsi)
622{
623 paging_expecting_tmsi = tmsi;
624 paging_expecting_imsi = NULL;
625}
626
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100627/* override, requires '-Wl,--wrap=ran_peers_down_paging' */
628int __real_ran_peers_down_paging(struct sccp_ran_inst *sri, enum CELL_IDENT page_where, struct vlr_subscr *vsub,
629 enum paging_cause cause);
630int __wrap_ran_peers_down_paging(struct sccp_ran_inst *sri, enum CELL_IDENT page_where, struct vlr_subscr *vsub,
631 enum paging_cause cause)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100632{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100633 log("paging request (%s) to %s on %s", paging_cause_name(cause), vlr_subscr_name(vsub),
634 osmo_rat_type_name(sri->ran->type));
635
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100636 OSMO_ASSERT(paging_expecting_imsi || (paging_expecting_tmsi != GSM_RESERVED_TMSI));
637 if (paging_expecting_imsi)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100638 VERBOSE_ASSERT(strcmp(paging_expecting_imsi, vsub->imsi), == 0, "%d");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200639 if (paging_expecting_tmsi != GSM_RESERVED_TMSI) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100640 VERBOSE_ASSERT(paging_expecting_tmsi, == vsub->tmsi, "0x%08x");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200641 }
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100642 paging_sent = true;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100643 return 1;
644}
645
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100646void clear_vlr()
647{
648 struct vlr_subscr *vsub, *n;
649 llist_for_each_entry_safe(vsub, n, &net->vlr->subscribers, list) {
650 vlr_subscr_free(vsub);
651 }
652
653 net->authentication_required = false;
Harald Welte7b222aa2017-12-23 19:30:32 +0100654 net->a5_encryption_mask = (1 << 0);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100655 net->vlr->cfg.check_imei_rqd = false;
656 net->vlr->cfg.assign_tmsi = false;
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200657 net->vlr->cfg.retrieve_imeisv_early = false;
658 net->vlr->cfg.retrieve_imeisv_ciphered = false;
Neels Hofmeyr7b1418e2017-10-29 02:12:16 +0100659 net->vlr->cfg.auth_tuple_max_reuse_count = 0;
660 net->vlr->cfg.auth_reuse_old_sets_on_error = false;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100661
Neels Hofmeyr7814a832018-12-26 00:40:18 +0100662 rx_from_ran = OSMO_RAT_GERAN_A;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100663 auth_request_sent = false;
664 auth_request_expect_rand = NULL;
665 auth_request_expect_autn = NULL;
666
Neels Hofmeyrdbabfd32018-03-10 02:06:47 +0100667 cipher_mode_cmd_sent = false;
668 cipher_mode_cmd_sent_with_imeisv = false;
669 cipher_mode_expect_kc = NULL;
670
671 security_mode_ctrl_sent = false;
672 security_mode_expect_ck = NULL;
673 security_mode_expect_ik = NULL;
674
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100675 next_rand_byte = 0;
676
Philipp Maierfbf66102017-04-09 12:32:51 +0200677 iu_release_expected = false;
678 iu_release_sent = false;
679 bssap_clear_expected = false;
680 bssap_clear_sent = false;
681
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100682 osmo_gettimeofday_override = false;
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200683
Neels Hofmeyr81938fd2022-01-14 03:39:58 +0100684 memset(expecting_crcx, 0, sizeof(expecting_crcx));
685 memset(got_crcx, 0, sizeof(got_crcx));
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200686
687 bssap_assignment_expected = false;
688 bssap_assignment_sent = false;
689 iu_rab_assignment_expected = false;
690 iu_rab_assignment_sent = false;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100691}
692
693static struct log_info_cat test_categories[] = {
694 [DMSC] = {
695 .name = "DMSC",
696 .description = "Mobile Switching Center",
697 .enabled = 1, .loglevel = LOGL_DEBUG,
698 },
699 [DRLL] = {
700 .name = "DRLL",
701 .description = "A-bis Radio Link Layer (RLL)",
702 .enabled = 1, .loglevel = LOGL_DEBUG,
703 },
704 [DMM] = {
705 .name = "DMM",
706 .description = "Layer3 Mobility Management (MM)",
707 .enabled = 1, .loglevel = LOGL_DEBUG,
708 },
709 [DRR] = {
710 .name = "DRR",
711 .description = "Layer3 Radio Resource (RR)",
712 .enabled = 1, .loglevel = LOGL_DEBUG,
713 },
714 [DCC] = {
715 .name = "DCC",
716 .description = "Layer3 Call Control (CC)",
Neels Hofmeyr12e17be2018-03-12 23:59:37 +0100717 .enabled = 1, .loglevel = LOGL_DEBUG,
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100718 },
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100719 [DVLR] = {
720 .name = "DVLR",
721 .description = "Visitor Location Register",
722 .enabled = 1, .loglevel = LOGL_DEBUG,
723 },
724 [DREF] = {
725 .name = "DREF",
726 .description = "Reference Counting",
727 .enabled = 1, .loglevel = LOGL_DEBUG,
728 },
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200729 [DPAG] = {
730 .name = "DPAG",
731 .description = "Paging Subsystem",
732 .enabled = 1, .loglevel = LOGL_DEBUG,
733 },
734 [DIUCS] = {
735 .name = "DIUCS",
736 .description = "Iu-CS Protocol",
737 .enabled = 1, .loglevel = LOGL_DEBUG,
738 },
Neels Hofmeyra99b4272017-11-21 17:13:23 +0100739 [DMNCC] = {
740 .name = "DMNCC",
741 .description = "MNCC API for Call Control application",
742 .enabled = 1, .loglevel = LOGL_DEBUG,
743 },
Neels Hofmeyr46c06e22019-01-04 17:42:05 +0100744 [DBSSAP] = {
745 .name = "DBSSAP",
746 .description = "BSSAP Protocol (A Interface)",
747 .enabled = 1, .loglevel = LOGL_DEBUG,
748 },
Neels Hofmeyr979b0572019-05-09 15:24:49 +0200749 [DSS] = {
750 .name = "DSS",
751 .description = "Supplementary Services",
752 .enabled = 1, .loglevel = LOGL_DEBUG,
753 },
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100754};
755
756static struct log_info info = {
757 .cat = test_categories,
758 .num_cat = ARRAY_SIZE(test_categories),
759};
760
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100761struct gsm_mncc *on_call_release_mncc_sends_to_cc_data = NULL;
762
Neels Hofmeyra99b4272017-11-21 17:13:23 +0100763int mncc_recv(struct gsm_network *net, struct msgb *msg)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100764{
Neels Hofmeyra99b4272017-11-21 17:13:23 +0100765 struct gsm_mncc *mncc = (void*)msg->data;
Neels Hofmeyr3c323dc2022-01-14 03:35:08 +0100766 if (mncc->msg_type == MNCC_RTP_CREATE) {
767 struct gsm_mncc_rtp *rtp = (void *)msg->data;
768 log("MSC --> MNCC: callref 0x%x: %s\n%s", rtp->callref,
769 get_mncc_name(rtp->msg_type),
770 rtp->sdp);
771 OSMO_STRLCPY_ARRAY(cc_to_mncc_tx_last_sdp, rtp->sdp);
772 } else {
773 log("MSC --> MNCC: callref 0x%x: %s\n%s", mncc->callref,
774 get_mncc_name(mncc->msg_type),
775 mncc->sdp);
776 OSMO_STRLCPY_ARRAY(cc_to_mncc_tx_last_sdp, mncc->sdp);
777 }
Neels Hofmeyra99b4272017-11-21 17:13:23 +0100778
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100779 if (mncc->msg_type == MNCC_REL_IND && on_call_release_mncc_sends_to_cc_data) {
780
781 log("MNCC: callref 0x%x: Call Release triggering %s", mncc->callref,
782 get_mncc_name(on_call_release_mncc_sends_to_cc_data->msg_type));
783
Neels Hofmeyr52558742019-05-09 01:23:09 +0200784 mncc_tx_to_cc(net,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100785 on_call_release_mncc_sends_to_cc_data);
786
787 on_call_release_mncc_sends_to_cc_data = NULL;
788 return 0;
789 }
790
Neels Hofmeyra99b4272017-11-21 17:13:23 +0100791 OSMO_ASSERT(cc_to_mncc_tx_expected_msg_type);
792 if (cc_to_mncc_tx_expected_msg_type != mncc->msg_type) {
793 log("Mismatch! Expected MNCC msg type: %s",
794 get_mncc_name(cc_to_mncc_tx_expected_msg_type));
795 abort();
796 }
797
798 if (strcmp(cc_to_mncc_tx_expected_imsi, mncc->imsi)) {
799 log("Mismatch! Expected MNCC msg IMSI: '%s', got '%s'",
800 cc_to_mncc_tx_expected_imsi,
801 mncc->imsi);
802 abort();
803 }
804
805 cc_to_mncc_tx_confirmed = true;
806 cc_to_mncc_tx_got_callref = mncc->callref;
807 cc_to_mncc_tx_expected_imsi = NULL;
808 cc_to_mncc_tx_expected_msg_type = 0;
809 talloc_free(msg);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100810 return 0;
811}
812
Harald Welte1ea6baf2018-07-31 19:40:52 +0200813struct osmo_gsup_client *
Stefan Sperlingafa030d2018-12-06 12:06:59 +0100814__real_osmo_gsup_client_create2(struct ipaccess_unit *ipa_dev, const char *ip_addr,
815 unsigned int tcp_port, osmo_gsup_client_read_cb_t read_cb,
816 struct osmo_oap_client_config *oap_config);
Harald Welte1ea6baf2018-07-31 19:40:52 +0200817struct osmo_gsup_client *
Stefan Sperlingafa030d2018-12-06 12:06:59 +0100818__wrap_osmo_gsup_client_create2(struct ipaccess_unit *ipa_dev, const char *ip_addr,
819 unsigned int tcp_port, osmo_gsup_client_read_cb_t read_cb,
820 struct osmo_oap_client_config *oap_config)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100821{
Harald Welte1ea6baf2018-07-31 19:40:52 +0200822 struct osmo_gsup_client *gsupc;
823 gsupc = talloc_zero(msc_vlr_tests_ctx, struct osmo_gsup_client);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100824 OSMO_ASSERT(gsupc);
825 return gsupc;
826}
827
828/* override, requires '-Wl,--wrap=gsup_client_send' */
Harald Welte1ea6baf2018-07-31 19:40:52 +0200829int __real_osmo_gsup_client_send(struct osmo_gsup_client *gsupc, struct msgb *msg);
830int __wrap_osmo_gsup_client_send(struct osmo_gsup_client *gsupc, struct msgb *msg)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100831{
Max34d306b2019-01-15 18:37:31 +0100832 uint8_t buf[512];
833 int len;
834
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100835 fprintf(stderr, "GSUP --> HLR: %s: %s\n",
Max34d306b2019-01-15 18:37:31 +0100836 osmo_gsup_message_type_name(msg->data[0]), osmo_hexdump_nospc(msg->data, msg->len));
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100837
838 OSMO_ASSERT(gsup_tx_expected);
Max34d306b2019-01-15 18:37:31 +0100839 OSMO_ASSERT(strlen(gsup_tx_expected) <= (sizeof(buf) * 2));
840
841 len = osmo_hexparse(gsup_tx_expected, buf, sizeof(buf));
842 if (len < 1)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100843 abort();
Max34d306b2019-01-15 18:37:31 +0100844
Neels Hofmeyrbe5f0332018-12-26 01:11:57 +0100845 /* Compare only the length expected. Extra data is fine, to not care about new GSUP IEs invented later. */
846 if (msg->len < len) {
847 fprintf(stderr, "ERROR: GSUP message too short, expected '%s'\n", gsup_tx_expected);
Max34d306b2019-01-15 18:37:31 +0100848 abort();
Neels Hofmeyrbe5f0332018-12-26 01:11:57 +0100849 }
850
851 if (memcmp(msg->data, buf, len)) {
852 fprintf(stderr, "ERROR: GSUP message mismatch, expected it to start with '%s'\n", gsup_tx_expected);
853 abort();
854 }
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100855
856 talloc_free(msg);
857 gsup_tx_confirmed = true;
858 gsup_tx_expected = NULL;
859 return 0;
860}
861
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200862struct rtp_stream fake_rtp[2] = {
863 {
864 .dir = RTP_TO_RAN,
865 .local = {
866 .ip = "10.23.42.1",
867 .port = 99,
868 },
869 .remote = {
870 .ip = "10.23.42.2",
871 .port = 100,
872 },
873 },
874 {
875 .dir = RTP_TO_CN,
876 .local = {
877 .ip = "10.23.42.1",
878 .port = 23,
879 },
880 .remote = {
881 .ip = "10.23.42.2",
882 .port = 42,
883 },
884 },
885};
886
887void expect_crcx(enum rtp_direction towards)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100888{
Neels Hofmeyr81938fd2022-01-14 03:39:58 +0100889 OSMO_ASSERT(!expecting_crcx[towards]);
890 expecting_crcx[towards] = true;
891 got_crcx[towards] = false;
892}
893
894bool crcx_scheduled(enum rtp_direction towards)
895{
896 return got_crcx[towards];
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200897}
898
899/* override, requires '-Wl,--wrap=call_leg_ensure_ci' */
900int __real_call_leg_ensure_ci(struct call_leg *cl, enum rtp_direction dir, uint32_t call_id, struct gsm_trans *for_trans,
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100901 const struct sdp_audio_codecs *codecs_if_known,
902 const struct osmo_sockaddr_str *remote_addr_if_known);
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200903int __wrap_call_leg_ensure_ci(struct call_leg *cl, enum rtp_direction dir, uint32_t call_id, struct gsm_trans *for_trans,
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100904 const struct sdp_audio_codecs *codecs_if_known,
905 const struct osmo_sockaddr_str *remote_addr_if_known)
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200906{
907 if (!cl->rtp[dir]) {
Andreas Eversberg712b28e2023-06-21 11:17:26 +0200908 log("MGW <--CRCX to %s-- MSC: call_id=0x%x codecs=%s", rtp_direction_name(dir), call_id,
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100909 codecs_if_known ? sdp_audio_codecs_to_str(codecs_if_known) : "unset");
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200910
Neels Hofmeyr81938fd2022-01-14 03:39:58 +0100911 OSMO_ASSERT(expecting_crcx[dir]);
912 expecting_crcx[dir] = false;
913 got_crcx[dir] = true;
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200914
915 call_leg_ensure_rtp_alloc(cl, dir, call_id, for_trans);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100916 if (codecs_if_known)
917 rtp_stream_set_codecs(cl->rtp[dir], codecs_if_known);
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200918 if (remote_addr_if_known && osmo_sockaddr_str_is_nonzero(remote_addr_if_known))
919 rtp_stream_set_remote_addr(cl->rtp[dir], remote_addr_if_known);
920 }
921
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100922 return 0;
923}
924
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +0200925void crcx_ok(enum rtp_direction dir)
926{
927 struct msc_a *msc_a = msub_msc_a(g_msub);
928 struct call_leg *cl = msc_a->cc.call_leg;
929 OSMO_ASSERT(cl);
930 OSMO_ASSERT(cl->rtp[dir]);
931 osmo_sockaddr_str_from_str(&cl->rtp[dir]->local, "10.23.23.1", 23);
932 //osmo_sockaddr_str_from_str(&cl->rtp[dir].remote, "10.42.42.1", 42);
933 log("MGW --CRCX OK to %s--> MSC", rtp_direction_name(dir));
934 osmo_fsm_inst_dispatch(cl->fi, CALL_LEG_EV_RTP_STREAM_ADDR_AVAILABLE, cl->rtp[dir]);
935}
936
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100937static int fake_vlr_tx_lu_acc(void *msc_conn_ref, uint32_t send_tmsi)
938{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100939 struct msc_a *msc_a = msc_conn_ref;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100940 if (send_tmsi == GSM_RESERVED_TMSI)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100941 btw("sending LU Accept for %s", msc_a->c.fi->id);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100942 else
943 btw("sending LU Accept for %s, with TMSI 0x%08x",
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100944 msc_a->c.fi->id, send_tmsi);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100945 lu_result_sent |= RES_ACCEPT;
946 return 0;
947}
948
Neels Hofmeyr15809592018-04-06 02:57:51 +0200949static int fake_vlr_tx_lu_rej(void *msc_conn_ref, enum gsm48_reject_value cause)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100950{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100951 struct msc_a *msc_a = msc_conn_ref;
952 btw("sending LU Reject for %s, cause %u", msc_a->c.fi->id, cause);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100953 lu_result_sent |= RES_REJECT;
954 return 0;
955}
956
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100957static int fake_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum osmo_cm_service_type cm_service_type,
958 enum gsm48_reject_value cause)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100959{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100960 struct msc_a *msc_a = msc_conn_ref;
961 btw("sending CM Service Reject (%s) for %s, cause: %s",
962 osmo_cm_service_type_name(cm_service_type), msc_a->c.fi->id, gsm48_reject_value_name(cause));
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100963 cm_service_result_sent |= RES_REJECT;
964 return 0;
965}
966
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100967static int fake_vlr_tx_auth_req(void *msc_conn_ref, struct vlr_auth_tuple *at,
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100968 bool send_autn)
969{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100970 struct msc_a *msc_a = msc_conn_ref;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100971 char *hex;
972 bool ok = true;
973 btw("sending %s Auth Request for %s: tuple use_count=%d key_seq=%d auth_types=0x%x and...",
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100974 send_autn? "UMTS" : "GSM", msc_a->c.fi->id,
Neels Hofmeyr6a29d322017-01-25 15:04:16 +0100975 at->use_count, at->key_seq, at->vec.auth_types);
976
977 hex = osmo_hexdump_nospc((void*)&at->vec.rand, sizeof(at->vec.rand));
978 btw("...rand=%s", hex);
979 if (!auth_request_expect_rand
980 || strcmp(hex, auth_request_expect_rand) != 0) {
981 ok = false;
982 log("FAILURE: expected rand=%s",
983 auth_request_expect_rand ? auth_request_expect_rand : "-");
984 }
985
986 if (send_autn) {
987 hex = osmo_hexdump_nospc((void*)&at->vec.autn, sizeof(at->vec.autn));
988 btw("...autn=%s", hex);
989 if (!auth_request_expect_autn
990 || strcmp(hex, auth_request_expect_autn) != 0) {
991 ok = false;
992 log("FAILURE: expected autn=%s",
993 auth_request_expect_autn ? auth_request_expect_autn : "-");
994 }
995 } else if (auth_request_expect_autn) {
996 ok = false;
997 log("FAILURE: no AUTN sent, expected AUTN = %s",
998 auth_request_expect_autn);
999 }
1000
1001 if (send_autn)
1002 btw("...expecting res=%s",
1003 osmo_hexdump_nospc((void*)&at->vec.res, at->vec.res_len));
1004 else
1005 btw("...expecting sres=%s",
1006 osmo_hexdump_nospc((void*)&at->vec.sres, sizeof(at->vec.sres)));
1007
1008 auth_request_sent = ok;
1009 return 0;
1010}
1011
1012static int fake_vlr_tx_auth_rej(void *msc_conn_ref)
1013{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001014 struct msc_a *msc_a = msc_conn_ref;
1015 btw("sending Auth Reject for %s", msc_a->c.fi->id);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001016 return 0;
1017}
1018
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001019void ms_sends_ciphering_mode_complete(const char *inner_ran_msg)
Neels Hofmeyrda21a522018-03-02 01:50:09 +01001020{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001021 struct ran_msg ran_dec;
Neels Hofmeyrdbabfd32018-03-10 02:06:47 +01001022
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001023 msc_a_get(msub_msc_a(g_msub), __func__);
1024
1025 ran_dec = (struct ran_msg){
1026 .msg_type = RAN_MSG_CIPHER_MODE_COMPLETE,
1027 };
1028 fake_msc_a_ran_dec(&ran_dec);
1029
1030 if (inner_ran_msg) {
1031 struct msgb *msg = msgb_from_hex("cipher_mode_complete_ran", 1024, inner_ran_msg);
1032 msg->l1h = msg->l2h = msg->l3h = msg->data;
1033 ran_dec = (struct ran_msg){
1034 .msg_type = RAN_MSG_DTAP,
1035 .dtap = msg,
1036 };
1037 patch_l3_seq_nr(msg);
1038 fake_msc_a_ran_dec(&ran_dec);
1039 msgb_free(msg);
Neels Hofmeyrdbabfd32018-03-10 02:06:47 +01001040 }
Neels Hofmeyrda21a522018-03-02 01:50:09 +01001041
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001042 msc_a_put(msub_msc_a(g_msub), __func__);
Neels Hofmeyrda21a522018-03-02 01:50:09 +01001043
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001044 if (!conn_exists(g_msub))
1045 g_msub = NULL;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001046}
1047
Alexander Couzens2aaff752021-10-19 17:09:11 +02001048void ms_sends_security_mode_complete(uint8_t utran_encryption)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001049{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001050 struct ran_msg ran_dec;
1051
1052 ran_dec = (struct ran_msg){
1053 .msg_type = RAN_MSG_CIPHER_MODE_COMPLETE,
Alexander Couzens2aaff752021-10-19 17:09:11 +02001054 .cipher_mode_complete.utran_encryption = utran_encryption,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001055 };
1056 fake_msc_a_ran_dec(&ran_dec);
1057
1058 if (!conn_exists(g_msub))
1059 g_msub = NULL;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001060}
1061
Neels Hofmeyrcec51b32023-03-01 03:47:45 +01001062void ms_sends_assignment_complete(const char *sdp_codec_name)
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +02001063{
1064 struct ran_msg ran_dec;
Neels Hofmeyrcec51b32023-03-01 03:47:45 +01001065 const struct codec_mapping *m = codec_mapping_by_subtype_name(sdp_codec_name);
1066 OSMO_ASSERT(m);
1067 OSMO_ASSERT(m->has_gsm0808_speech_codec);
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +02001068
1069 ran_dec = (struct ran_msg){
1070 .msg_type = RAN_MSG_ASSIGNMENT_COMPLETE,
1071 .assignment_complete = {
Pau Espin Pedrol9de384a2022-01-07 16:27:04 +01001072 .codec_present = true,
Neels Hofmeyrcec51b32023-03-01 03:47:45 +01001073 .codec = m->gsm0808_speech_codec,
1074 .codec_with_iuup = (rx_from_ran == OSMO_RAT_UTRAN_IU),
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +02001075 },
1076 };
Neels Hofmeyr8159c952022-08-06 16:23:31 +02001077 osmo_sockaddr_str_from_str(&ran_dec.assignment_complete.remote_rtp, "1.2.3.4", 1234);
Neels Hofmeyr3f391dd2019-08-29 03:53:11 +02001078 fake_msc_a_ran_dec(&ran_dec);
1079
1080 if (!conn_exists(g_msub))
1081 g_msub = NULL;
1082}
1083
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001084void ran_sends_clear_complete()
Neels Hofmeyr4068ab22018-04-01 20:55:54 +02001085{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001086 struct ran_msg ran_dec;
Neels Hofmeyr4068ab22018-04-01 20:55:54 +02001087
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001088 ran_dec = (struct ran_msg){
1089 .msg_type = RAN_MSG_CLEAR_COMPLETE,
1090 };
1091 fake_msc_a_ran_dec(&ran_dec);
1092
1093 if (!conn_exists(g_msub))
1094 g_msub = NULL;
Neels Hofmeyr4068ab22018-04-01 20:55:54 +02001095}
1096
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001097const struct timeval fake_time_start_time = { 123, 456 };
1098
1099void fake_time_start()
1100{
Stefan Sperlingdefc3c82018-05-15 14:48:04 +02001101 struct timespec *clock_override;
1102
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001103 osmo_gettimeofday_override_time = fake_time_start_time;
1104 osmo_gettimeofday_override = true;
Stefan Sperlingdefc3c82018-05-15 14:48:04 +02001105 clock_override = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
1106 OSMO_ASSERT(clock_override);
1107 clock_override->tv_sec = fake_time_start_time.tv_sec;
1108 clock_override->tv_nsec = fake_time_start_time.tv_usec * 1000;
1109 osmo_clock_override_enable(CLOCK_MONOTONIC, true);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001110 fake_time_passes(0, 0);
1111}
1112
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001113static struct {
1114 bool verbose;
1115 int run_test_nr;
1116} cmdline_opts = {
1117 .verbose = false,
1118 .run_test_nr = -1,
1119};
1120
1121static void print_help(const char *program)
1122{
1123 printf("Usage:\n"
1124 " %s [-v] [N [N...]]\n"
1125 "Options:\n"
1126 " -h --help show this text.\n"
1127 " -v --verbose print source file and line numbers\n"
1128 " N run only the Nth test (first test is N=1)\n",
1129 program
1130 );
1131}
1132
1133static void handle_options(int argc, char **argv)
1134{
1135 while (1) {
1136 int option_index = 0, c;
1137 static struct option long_options[] = {
1138 {"help", 0, 0, 'h'},
1139 {"verbose", 1, 0, 'v'},
1140 {0, 0, 0, 0}
1141 };
1142
1143 c = getopt_long(argc, argv, "hv",
1144 long_options, &option_index);
1145 if (c == -1)
1146 break;
1147
1148 switch (c) {
1149 case 'h':
1150 print_help(argv[0]);
1151 exit(0);
1152 case 'v':
1153 cmdline_opts.verbose = true;
1154 break;
1155 default:
1156 /* catch unknown options *as well as* missing arguments. */
1157 fprintf(stderr, "Error in command line options. Exiting.\n");
1158 exit(-1);
1159 break;
1160 }
1161 }
1162}
1163
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001164static void run_tests(int nr)
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001165{
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001166 int test_nr;
Neels Hofmeyr08b38282018-03-30 23:04:04 +02001167
Max5e2e9bd2018-02-06 19:31:08 +01001168 nr--; /* arg's first test is 1, in here it's 0 */
1169 for (test_nr = 0; msc_vlr_tests[test_nr]; test_nr++) {
Neels Hofmeyrdbb3c722021-02-07 23:53:07 +01001170 size_t talloc_blocks_before_test;
1171
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001172 if (nr >= 0 && test_nr != nr)
1173 continue;
1174
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001175 if (cmdline_opts.verbose)
1176 fprintf(stderr, "(test nr %d)\n", test_nr + 1);
1177
Neels Hofmeyrdbb3c722021-02-07 23:53:07 +01001178 talloc_blocks_before_test = talloc_total_blocks(msc_vlr_tests_ctx);
1179
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001180 msc_vlr_tests[test_nr]();
1181
Neels Hofmeyrdbb3c722021-02-07 23:53:07 +01001182 if (talloc_total_blocks(msc_vlr_tests_ctx) != talloc_blocks_before_test) {
1183 fprintf(stderr, "ERROR: talloc leak: %zu blocks\n",
1184 talloc_total_blocks(msc_vlr_tests_ctx) - talloc_blocks_before_test);
1185 talloc_report_full(msc_vlr_tests_ctx, stderr);
1186 fprintf(stderr, "\n");
1187 }
1188
1189 if (talloc_total_blocks(msgb_ctx) > 1) {
1190 fprintf(stderr, "ERROR: msgb leak:\n");
1191 talloc_report_full(msgb_ctx, stderr);
1192 fprintf(stderr, "\n");
1193 }
1194
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001195 if (cmdline_opts.verbose)
1196 fprintf(stderr, "(test nr %d)\n", test_nr + 1);
Max29ce08a2018-02-06 18:46:57 +01001197 }
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001198}
1199
Max5e60de62018-02-07 12:56:09 +01001200struct gsm_network *test_net(void *ctx)
1201{
Neels Hofmeyr7f484202018-02-27 12:59:45 +01001202 struct gsm_network *net = gsm_network_init(ctx, mncc_recv);
Pau Espin Pedrolb44cf2d2022-10-17 18:09:15 +02001203 struct mgcp_client *client;
Max5e60de62018-02-07 12:56:09 +01001204
1205 net->gsup_server_addr_str = talloc_strdup(net, "no_gsup_server");
1206 net->gsup_server_port = 0;
1207
1208 OSMO_ASSERT(msc_vlr_alloc(net) == 0);
Max5e60de62018-02-07 12:56:09 +01001209 OSMO_ASSERT(net->vlr);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001210 OSMO_ASSERT(msc_gsup_client_start(net) == 0);
1211 OSMO_ASSERT(net->gcm);
1212 OSMO_ASSERT(msc_vlr_start(net) == 0);
Max5e60de62018-02-07 12:56:09 +01001213
1214 net->vlr->ops.tx_lu_acc = fake_vlr_tx_lu_acc;
1215 net->vlr->ops.tx_lu_rej = fake_vlr_tx_lu_rej;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001216 net->vlr->ops.tx_cm_serv_acc = msc_vlr_tx_cm_serv_acc;
Max5e60de62018-02-07 12:56:09 +01001217 net->vlr->ops.tx_cm_serv_rej = fake_vlr_tx_cm_serv_rej;
1218 net->vlr->ops.tx_auth_req = fake_vlr_tx_auth_req;
1219 net->vlr->ops.tx_auth_rej = fake_vlr_tx_auth_rej;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001220 net->vlr->ops.set_ciph_mode = msc_a_vlr_set_cipher_mode;
1221
1222 /* Allocate fake SCCP Ran Instances */
1223 net->a.sri = talloc_zero(net, struct sccp_ran_inst);
1224 *net->a.sri = (struct sccp_ran_inst){
1225 .ran = &test_ran_infra[OSMO_RAT_GERAN_A],
1226 };
1227 INIT_LLIST_HEAD(&net->a.sri->ran_peers);
1228 INIT_LLIST_HEAD(&net->a.sri->ran_conns);
1229
1230 net->iu.sri = talloc_zero(net, struct sccp_ran_inst);
1231 *net->iu.sri = (struct sccp_ran_inst){
1232 .ran = &test_ran_infra[OSMO_RAT_UTRAN_IU],
1233 };
1234 INIT_LLIST_HEAD(&net->iu.sri->ran_peers);
1235 INIT_LLIST_HEAD(&net->iu.sri->ran_conns);
1236
1237 net->mgw.tdefs = g_mgw_tdefs;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001238 net->mgw.tdefs = g_mgw_tdefs;
Pau Espin Pedrol9e3bab92023-06-13 19:57:57 +02001239 net->mgw.conf = mgcp_client_conf_alloc(net);
Pau Espin Pedrolb44cf2d2022-10-17 18:09:15 +02001240 net->mgw.mgw_pool = mgcp_client_pool_alloc(net);
Pau Espin Pedrol9e3bab92023-06-13 19:57:57 +02001241 client = mgcp_client_init(net, net->mgw.conf);
Pau Espin Pedrolb44cf2d2022-10-17 18:09:15 +02001242 mgcp_client_pool_register_single(net->mgw.mgw_pool, client);
Max5e60de62018-02-07 12:56:09 +01001243 return net;
1244}
1245
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001246int main(int argc, char **argv)
1247{
1248 handle_options(argc, argv);
1249
Neels Hofmeyre4f7e712019-03-24 21:07:33 +01001250 osmo_fsm_term_safely(true);
1251
Neels Hofmeyrc01e9092018-03-22 15:56:49 +01001252 msc_vlr_tests_ctx = talloc_named_const(NULL, 0, "msc_vlr_tests_ctx");
1253 msgb_ctx = msgb_talloc_ctx_init(msc_vlr_tests_ctx, 0);
Neels Hofmeyr08b38282018-03-30 23:04:04 +02001254 osmo_init_logging2(msc_vlr_tests_ctx, &info);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001255
1256 _log_lines = cmdline_opts.verbose;
1257
1258 OSMO_ASSERT(osmo_stderr_target);
1259 log_set_use_color(osmo_stderr_target, 0);
1260 log_set_print_timestamp(osmo_stderr_target, 0);
Pau Espin Pedrolcad22fd2021-02-19 13:37:00 +01001261 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001262 log_set_print_category(osmo_stderr_target, 1);
Pau Espin Pedrol8d02d992021-02-19 13:36:47 +01001263 log_set_print_category_hex(osmo_stderr_target, 0);
Max48131522019-01-16 12:47:39 +01001264 log_set_category_filter(osmo_stderr_target, DLSMS, 1, LOGL_DEBUG);
Philipp Maierce1f9732021-09-14 11:18:46 +02001265 log_set_category_filter(osmo_stderr_target, DLMGCP, 0, LOGL_NOTICE);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001266
Neels Hofmeyr39cb0dd2018-12-18 02:30:18 +01001267 if (cmdline_opts.verbose) {
Neels Hofmeyr39cb0dd2018-12-18 02:30:18 +01001268 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
1269 log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END);
1270 log_set_use_color(osmo_stderr_target, 1);
1271 log_set_print_level(osmo_stderr_target, 1);
1272 }
Neels Hofmeyr3f5b7802017-12-15 03:49:55 +01001273
Neels Hofmeyrc01e9092018-03-22 15:56:49 +01001274 net = test_net(msc_vlr_tests_ctx);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001275
1276 osmo_fsm_log_addr(false);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001277 osmo_fsm_log_timeouts(cmdline_opts.verbose);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001278
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001279 call_leg_init(net);
1280
1281 OSMO_ASSERT(osmo_fsm_register(&dummy_msc_i_fsm) == 0);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001282
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001283 clear_vlr();
1284
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001285 if (optind >= argc)
1286 run_tests(-1);
1287 else {
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001288 int arg;
1289 long int nr;
1290 for (arg = optind; arg < argc; arg++) {
Neels Hofmeyr9c848b52017-11-22 01:59:36 +01001291 errno = 0;
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001292 nr = strtol(argv[arg], NULL, 10);
1293 if (errno) {
1294 fprintf(stderr, "Invalid argument: %s\n",
1295 argv[arg]);
1296 exit(1);
1297 }
1298
Neels Hofmeyrdfdc61d2018-03-02 00:40:58 +01001299 run_tests(nr);
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001300 }
1301 }
1302
1303 printf("Done\n");
1304
Neels Hofmeyr6a29d322017-01-25 15:04:16 +01001305 return 0;
1306}