blob: 857a6a6911d3378246488288542084e7d5c7df31 [file] [log] [blame]
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001/* OsmoMSC - Circuit-Switched Core Network (MSC+VLR+HLR+SMSC) implementation
2 */
3
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01004/* (C) 2016-2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02005 * All Rights Reserved
6 *
7 * Based on OsmoNITB:
8 * (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
9 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
10 * All Rights Reserved
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Affero General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 *
25 */
26
Stefan Sperling1051c422018-12-13 10:16:49 +010027#include <stdbool.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020028#include <unistd.h>
29#include <time.h>
30#include <errno.h>
31#include <signal.h>
32#include <fcntl.h>
33#include <sys/stat.h>
34
35#define _GNU_SOURCE
36#include <getopt.h>
37
38/* build switches from the configure script */
39#include "../../bscconfig.h"
40
Neels Hofmeyr90843962017-09-04 15:04:35 +020041#include <osmocom/msc/db.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020042#include <osmocom/core/application.h>
43#include <osmocom/core/select.h>
44#include <osmocom/core/stats.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020045#include <osmocom/msc/debug.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020046#include <osmocom/abis/abis.h>
47#include <osmocom/abis/e1_input.h>
48#include <osmocom/core/talloc.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020049#include <osmocom/msc/signal.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020050#include <osmocom/msc/sms_queue.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020051#include <osmocom/vty/telnet_interface.h>
52#include <osmocom/vty/ports.h>
53#include <osmocom/vty/logging.h>
Harald Welte3db47c42018-02-14 00:40:05 +010054#include <osmocom/vty/misc.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020055#include <osmocom/msc/vty.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020056#include <osmocom/msc/mncc.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020057#include <osmocom/msc/rrlp.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020058#include <osmocom/ctrl/control_if.h>
59#include <osmocom/ctrl/control_vty.h>
60#include <osmocom/ctrl/ports.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020061#include <osmocom/msc/smpp.h>
Philipp Maierfbf66102017-04-09 12:32:51 +020062#include <osmocom/sigtran/osmo_ss7.h>
Neels Hofmeyr6c8afe12017-09-04 01:03:58 +020063#include <osmocom/mgcp_client/mgcp_client.h>
Harald Welte0df904d2018-12-03 11:00:04 +010064#include <osmocom/msc/sgs_iface.h>
Vadim Yanitskiy81635d32019-03-22 02:09:06 +070065#include <osmocom/msc/sgs_server.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010066#include <osmocom/msc/ran_infra.h>
67#include <osmocom/msc/ran_peer.h>
68#include <osmocom/msc/ran_msg_a.h>
69#include <osmocom/msc/msub.h>
70#include <osmocom/msc/call_leg.h>
71#include <osmocom/msc/msc_ho.h>
72#include <osmocom/msc/gsup_client_mux.h>
73#include <osmocom/msc/e_link.h>
74#include <osmocom/msc/mncc_call.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020075
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020076#ifdef BUILD_IU
77#include <osmocom/ranap/iu_client.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010078#include <asn1c/asn_internal.h>
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020079#endif
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020080
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020081static const char * const osmomsc_copyright =
82 "OsmoMSC - Osmocom Circuit-Switched Core Network implementation\r\n"
83 "Copyright (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
84 "Based on OsmoNITB:\r\n"
85 " (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>\r\n"
86 " (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>\r\n"
87 "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n"
88 "Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n\r\n"
89 "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
90 "This is free software: you are free to change and redistribute it.\r\n"
91 "There is NO WARRANTY, to the extent permitted by law.\r\n";
92
93void *tall_msc_ctx = NULL;
94
95/* satisfy deps from libbsc legacy.
96 TODO double check these */
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020097void *tall_map_ctx = NULL;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020098/* end deps from libbsc legacy. */
99
100static struct {
101 const char *database_name;
102 const char *config_file;
103 int daemonize;
104 const char *mncc_sock_path;
105 int use_db_counter;
106} msc_cmdline_config = {
Neels Hofmeyra2ed9b52018-12-05 00:38:28 +0100107 .database_name = "sms.db",
108 .config_file = "osmo-msc.cfg",
109 .use_db_counter = 1,
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200110};
111
112/* timer to store statistics */
113#define DB_SYNC_INTERVAL 60, 0
114#define EXPIRE_INTERVAL 10, 0
115
116static struct osmo_timer_list db_sync_timer;
117
Pau Espin Pedrolb8744862018-08-13 16:29:50 +0200118static int quit = 0;
119
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200120static void print_usage()
121{
Neels Hofmeyre9495382018-03-09 15:00:24 +0100122 printf("Usage: osmo-msc\n");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200123}
124
125static void print_help()
126{
127 printf(" Some useful help...\n");
128 printf(" -h --help This text.\n");
Harald Welte703f2ec2018-01-25 00:36:42 +0100129 printf(" -d option --debug=DCC:DMM:DRR: Enable debugging.\n");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200130 printf(" -D --daemonize Fork the process into a background daemon.\n");
131 printf(" -c --config-file filename The config file to use.\n");
132 printf(" -s --disable-color\n");
133 printf(" -l --database db-name The database to use.\n");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200134 printf(" -T --timestamp Prefix every log line with a timestamp.\n");
Pau Espin Pedrola232eeb2018-06-15 14:58:33 +0200135 printf(" -V --version Print the version of OsmoMSC.\n");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200136 printf(" -e --log-level number Set a global loglevel.\n");
137 printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200138 printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n");
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200139}
140
141static void handle_options(int argc, char **argv)
142{
143 while (1) {
144 int option_index = 0, c;
145 static struct option long_options[] = {
146 {"help", 0, 0, 'h'},
147 {"debug", 1, 0, 'd'},
148 {"daemonize", 0, 0, 'D'},
149 {"config-file", 1, 0, 'c'},
150 {"disable-color", 0, 0, 's'},
151 {"database", 1, 0, 'l'},
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200152 {"timestamp", 0, 0, 'T'},
153 {"version", 0, 0, 'V' },
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200154 {"log-level", 1, 0, 'e'},
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200155 {"mncc-sock-path", 1, 0, 'M'},
156 {"no-dbcounter", 0, 0, 'C'},
157 {0, 0, 0, 0}
158 };
159
Philipp Maierc4e7bd32017-12-05 12:14:47 +0100160 c = getopt_long(argc, argv, "hd:Dsl:TVc:e:CM:",
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200161 long_options, &option_index);
162 if (c == -1)
163 break;
164
165 switch (c) {
166 case 'h':
167 print_usage();
168 print_help();
169 exit(0);
170 case 's':
171 log_set_use_color(osmo_stderr_target, 0);
172 break;
173 case 'd':
174 log_parse_category_mask(osmo_stderr_target, optarg);
175 break;
176 case 'D':
177 msc_cmdline_config.daemonize = 1;
178 break;
179 case 'l':
180 msc_cmdline_config.database_name = optarg;
181 break;
182 case 'c':
183 msc_cmdline_config.config_file = optarg;
184 break;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200185 case 'T':
186 log_set_print_timestamp(osmo_stderr_target, 1);
187 break;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200188 case 'e':
189 log_set_log_level(osmo_stderr_target, atoi(optarg));
190 break;
191 case 'M':
192 msc_cmdline_config.mncc_sock_path = optarg;
193 break;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200194 case 'C':
195 msc_cmdline_config.use_db_counter = 0;
196 break;
197 case 'V':
198 print_version(1);
199 exit(0);
200 break;
201 default:
202 /* catch unknown options *as well as* missing arguments. */
203 fprintf(stderr, "Error in command line options. Exiting.\n");
204 exit(-1);
205 }
206 }
207}
208
209struct gsm_network *msc_network_alloc(void *ctx,
210 mncc_recv_cb_t mncc_recv)
211{
Neels Hofmeyr7f484202018-02-27 12:59:45 +0100212 struct gsm_network *net = gsm_network_init(ctx, mncc_recv);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200213 if (!net)
214 return NULL;
215
216 net->name_long = talloc_strdup(net, "OsmoMSC");
217 net->name_short = talloc_strdup(net, "OsmoMSC");
218
219 net->gsup_server_addr_str = talloc_strdup(net,
220 MSC_HLR_REMOTE_IP_DEFAULT);
221 net->gsup_server_port = MSC_HLR_REMOTE_PORT_DEFAULT;
222
Neels Hofmeyr6c8afe12017-09-04 01:03:58 +0200223 mgcp_client_conf_init(&net->mgw.conf);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100224 net->mgw.tdefs = g_mgw_tdefs;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200225
226 return net;
227}
228
229void msc_network_shutdown(struct gsm_network *net)
230{
231 /* nothing here yet */
232}
233
234static struct gsm_network *msc_network = NULL;
235
236extern void *tall_vty_ctx;
237static void signal_handler(int signal)
238{
239 fprintf(stdout, "signal %u received\n", signal);
240
241 switch (signal) {
242 case SIGINT:
Harald Welte28cd9442017-08-20 20:50:06 +0200243 case SIGTERM:
Pau Espin Pedrolb8744862018-08-13 16:29:50 +0200244 LOGP(DMSC, LOGL_NOTICE, "Terminating due to signal %d\n", signal);
245 quit++;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200246 break;
247 case SIGABRT:
248 osmo_generate_backtrace();
249 /* in case of abort, we want to obtain a talloc report
250 * and then return to the caller, who will abort the process */
251 case SIGUSR1:
252 talloc_report(tall_vty_ctx, stderr);
253 talloc_report_full(tall_msc_ctx, stderr);
254 break;
255 case SIGUSR2:
256 talloc_report_full(tall_vty_ctx, stderr);
257 break;
258 default:
259 break;
260 }
261}
262
263/* timer handling */
264static int _db_store_counter(struct osmo_counter *counter, void *data)
265{
266 return db_store_counter(counter);
267}
268
269static void db_sync_timer_cb(void *data)
270{
271 /* store counters to database and re-schedule */
272 osmo_counters_for_each(_db_store_counter, NULL);
273 osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
274}
275
Neels Hofmeyr7c075a22018-03-22 14:50:20 +0100276static int msc_vty_go_parent(struct vty *vty)
277{
278 switch (vty->node) {
279 case GSMNET_NODE:
280 vty->node = CONFIG_NODE;
281 vty->index = NULL;
282 break;
283 case SMPP_ESME_NODE:
284 vty->node = SMPP_NODE;
285 vty->index = NULL;
286 break;
287 case SMPP_NODE:
288 case MSC_NODE:
289 case MNCC_INT_NODE:
290 vty->node = CONFIG_NODE;
291 vty->index = NULL;
292 break;
293 case SUBSCR_NODE:
294 vty->node = ENABLE_NODE;
295 vty->index = NULL;
296 break;
297 default:
298 osmo_ss7_vty_go_parent(vty);
299 }
300
301 return vty->node;
302}
303
304static int msc_vty_is_config_node(struct vty *vty, int node)
305{
306 /* Check if libosmo-sccp declares the node in
307 * question as config node */
308 if (osmo_ss7_is_config_node(vty, node))
309 return 1;
310
311 switch (node) {
312 /* add items that are not config */
313 case SUBSCR_NODE:
314 case CONFIG_NODE:
315 return 0;
316
317 default:
318 return 1;
319 }
320}
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200321
322static struct vty_app_info msc_vty_info = {
323 .name = "OsmoMSC",
324 .version = PACKAGE_VERSION,
Neels Hofmeyr7c075a22018-03-22 14:50:20 +0100325 .go_parent_cb = msc_vty_go_parent,
326 .is_config_node = msc_vty_is_config_node,
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200327};
328
Philipp Maierfbf66102017-04-09 12:32:51 +0200329#define DEFAULT_M3UA_REMOTE_IP "127.0.0.1"
Neels Hofmeyrc875f842017-11-24 04:36:35 +0100330#define DEFAULT_PC "0.23.1"
Philipp Maierfbf66102017-04-09 12:32:51 +0200331
332static struct osmo_sccp_instance *sccp_setup(void *ctx, uint32_t cs7_instance,
333 const char *label, const char *default_pc_str)
334{
335 int default_pc = osmo_ss7_pointcode_parse(NULL, default_pc_str);
336 if (default_pc < 0)
337 return NULL;
338
339 return osmo_sccp_simple_client_on_ss7_id(ctx, cs7_instance, label, default_pc,
340 OSMO_SS7_ASP_PROT_M3UA,
341 0, NULL, /* local: use arbitrary port and 0.0.0.0. */
342 0, /* remote: use protocol default port */
343 DEFAULT_M3UA_REMOTE_IP);
344 /* Note: If a differing remote IP is to be used, it was already entered in the vty config at
345 * 'cs7' / 'asp' / 'remote-ip', and this default remote IP has no effect.
346 * Similarly, 'cs7' / 'listen' can specify the local IP address. */
347}
348
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100349static int ss7_setup(void *ctx, struct osmo_sccp_instance **sccp_a, struct osmo_sccp_instance **sccp_iu)
Philipp Maierfbf66102017-04-09 12:32:51 +0200350{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100351 uint32_t i_a = msc_network->a.cs7_instance;
352 uint32_t i_iu = msc_network->iu.cs7_instance;
353
354 const char *name_a = "OsmoMSC-A";
355 const char *name_iu = NULL;
356
Philipp Maierfbf66102017-04-09 12:32:51 +0200357#if BUILD_IU
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100358 if (i_a == i_iu)
359 name_a = name_iu = "OsmoMSC-A-Iu";
360 else
361 name_iu = "OsmoMSC-Iu";
Philipp Maierfbf66102017-04-09 12:32:51 +0200362#endif
363
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100364 *sccp_a = sccp_setup(ctx, i_a, name_a, DEFAULT_PC);
365 if (!*sccp_a)
366 return -EINVAL;
367
368 if (!name_iu) {
369 *sccp_iu = NULL;
370 return 0;
371 }
372
373 if (i_a == i_iu) {
374 *sccp_iu = *sccp_a;
375 return 0;
376 }
377
378 *sccp_iu = sccp_setup(ctx, i_iu, name_iu, DEFAULT_PC);
379 if (!*sccp_iu)
380 return -EINVAL;
381
Philipp Maierfbf66102017-04-09 12:32:51 +0200382 return 0;
383}
384
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100385static const struct log_info_cat msc_default_categories[] = {
386 [DRLL] = {
387 .name = "DRLL",
388 .description = "A-bis Radio Link Layer (RLL)",
389 .color = "\033[1;31m",
390 .enabled = 1, .loglevel = LOGL_NOTICE,
391 },
392 [DCC] = {
393 .name = "DCC",
394 .description = "Layer3 Call Control (CC)",
395 .color = "\033[1;32m",
396 .enabled = 1, .loglevel = LOGL_NOTICE,
397 },
398 [DMM] = {
399 .name = "DMM",
400 .description = "Layer3 Mobility Management (MM)",
401 .color = "\033[1;33m",
402 .enabled = 1, .loglevel = LOGL_NOTICE,
403 },
404 [DRR] = {
405 .name = "DRR",
406 .description = "Layer3 Radio Resource (RR)",
407 .color = "\033[1;34m",
408 .enabled = 1, .loglevel = LOGL_NOTICE,
409 },
410 [DMNCC] = {
411 .name = "DMNCC",
412 .description = "MNCC API for Call Control application",
413 .color = "\033[1;39m",
414 .enabled = 1, .loglevel = LOGL_NOTICE,
415 },
416 [DPAG] = {
417 .name = "DPAG",
418 .description = "Paging Subsystem",
419 .color = "\033[1;38m",
420 .enabled = 1, .loglevel = LOGL_NOTICE,
421 },
422 [DMSC] = {
423 .name = "DMSC",
424 .description = "Mobile Switching Center",
425 .enabled = 1, .loglevel = LOGL_NOTICE,
426 },
427 [DMGCP] = {
428 .name = "DMGCP",
429 .description = "Media Gateway Control Protocol",
430 .enabled = 1, .loglevel = LOGL_NOTICE,
431 },
432 [DHO] = {
433 .name = "DHO",
434 .description = "Hand-Over",
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100435 .color = "\033[1;38m",
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100436 .enabled = 1, .loglevel = LOGL_NOTICE,
437 },
438 [DDB] = {
439 .name = "DDB",
440 .description = "Database Layer",
441 .enabled = 1, .loglevel = LOGL_NOTICE,
442 },
443 [DREF] = {
444 .name = "DREF",
445 .description = "Reference Counting",
446 .enabled = 0, .loglevel = LOGL_NOTICE,
447 },
448 [DCTRL] = {
449 .name = "DCTRL",
450 .description = "Control interface",
451 .enabled = 1, .loglevel = LOGL_NOTICE,
452 },
453 [DSMPP] = {
454 .name = "DSMPP",
455 .description = "SMPP interface for external SMS apps",
Neels Hofmeyr88063dd2018-12-12 04:05:31 +0100456 .enabled = 1, .loglevel = LOGL_NOTICE,
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100457 },
458 [DRANAP] = {
459 .name = "DRANAP",
460 .description = "Radio Access Network Application Part Protocol",
Neels Hofmeyr88063dd2018-12-12 04:05:31 +0100461 .enabled = 1, .loglevel = LOGL_NOTICE,
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100462 },
463 [DVLR] = {
464 .name = "DVLR",
465 .description = "Visitor Location Register",
Neels Hofmeyr88063dd2018-12-12 04:05:31 +0100466 .enabled = 1, .loglevel = LOGL_NOTICE,
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100467 },
468 [DIUCS] = {
469 .name = "DIUCS",
470 .description = "Iu-CS Protocol",
Neels Hofmeyr88063dd2018-12-12 04:05:31 +0100471 .enabled = 1, .loglevel = LOGL_NOTICE,
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100472 },
473 [DBSSAP] = {
474 .name = "DBSSAP",
475 .description = "BSSAP Protocol (A Interface)",
476 .enabled = 1, .loglevel = LOGL_NOTICE,
477 },
Harald Welte0df904d2018-12-03 11:00:04 +0100478 [DSGS] = {
479 .name = "DSGS",
480 .description = "SGs Interface (SGsAP)",
481 .enabled = 1, .loglevel = LOGL_NOTICE,
482 },
483
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100484
485};
486
487static int filter_fn(const struct log_context *ctx, struct log_target *tar)
488{
489 const struct vlr_subscr *vsub = ctx->ctx[LOG_CTX_VLR_SUBSCR];
490
491 if ((tar->filter_map & (1 << LOG_FLT_VLR_SUBSCR)) != 0
492 && vsub && vsub == tar->filter_data[LOG_FLT_VLR_SUBSCR])
493 return 1;
494
495 return 0;
496}
497
498const struct log_info log_info = {
499 .filter_fn = filter_fn,
500 .cat = msc_default_categories,
501 .num_cat = ARRAY_SIZE(msc_default_categories),
502};
503
Neels Hofmeyrc01e9092018-03-22 15:56:49 +0100504extern void *tall_gsms_ctx;
505extern void *tall_call_ctx;
506extern void *tall_trans_ctx;
507
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200508int main(int argc, char **argv)
509{
510 int rc;
511
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100512 struct osmo_sccp_instance *sccp_a;
513 struct osmo_sccp_instance *sccp_iu;
514
Vadim Yanitskiy381370b2018-08-14 18:57:53 +0700515 /* Track the use of talloc NULL memory contexts */
516 talloc_enable_null_tracking();
517
Neels Hofmeyre4f7e712019-03-24 21:07:33 +0100518 osmo_fsm_term_safely(true);
519
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200520 msc_vty_info.copyright = osmomsc_copyright;
521
522 tall_msc_ctx = talloc_named_const(NULL, 1, "osmo_msc");
Harald Welte3db47c42018-02-14 00:40:05 +0100523 msc_vty_info.tall_ctx = tall_msc_ctx;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200524
Neels Hofmeyrc01e9092018-03-22 15:56:49 +0100525 msgb_talloc_ctx_init(tall_msc_ctx, 0);
Pau Espin Pedrol060a6c42018-08-16 19:09:21 +0200526 osmo_signal_talloc_ctx_init(tall_msc_ctx);
Neels Hofmeyrc01e9092018-03-22 15:56:49 +0100527 tall_gsms_ctx = talloc_named_const(tall_msc_ctx, 0, "sms");
528 tall_call_ctx = talloc_named_const(tall_msc_ctx, 0, "gsm_call");
529 tall_trans_ctx = talloc_named_const(tall_msc_ctx, 0, "transaction");
530
Neels Hofmeyr08b38282018-03-30 23:04:04 +0200531 osmo_init_logging2(tall_msc_ctx, &log_info);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100532
533 osmo_fsm_log_timeouts(true);
534 osmo_fsm_log_addr(true);
535
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200536 osmo_stats_init(tall_msc_ctx);
537
538 /* For --version, vty_init() must be called before handling options */
539 vty_init(&msc_vty_info);
540
Philipp Maierfbf66102017-04-09 12:32:51 +0200541 osmo_ss7_init();
542 osmo_ss7_vty_init_asp(tall_msc_ctx);
Neels Hofmeyr86ed06c2018-09-27 01:54:32 +0200543 osmo_sccp_vty_init();
Philipp Maierfbf66102017-04-09 12:32:51 +0200544
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200545 /* Parse options */
546 handle_options(argc, argv);
547
Neels Hofmeyrfb153cb2018-12-05 00:47:31 +0100548 /* Allocate global gsm_network struct.
549 * At first set the internal MNCC as default, may be changed below according to cfg or cmdline option. */
550 msc_network = msc_network_alloc(tall_msc_ctx, int_mncc_recv);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200551 if (!msc_network)
552 return -ENOMEM;
553
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100554 call_leg_init(msc_network);
555 mncc_call_fsm_init(msc_network);
556
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200557 if (msc_vlr_alloc(msc_network)) {
558 fprintf(stderr, "Failed to allocate VLR\n");
559 exit(1);
560 }
561
562 ctrl_vty_init(tall_msc_ctx);
563 logging_vty_add_cmds(&log_info);
Harald Welte3db47c42018-02-14 00:40:05 +0100564 osmo_talloc_vty_add_cmds();
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200565 msc_vty_init(msc_network);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200566
567#ifdef BUILD_SMPP
568 if (smpp_openbsc_alloc_init(tall_msc_ctx) < 0)
569 return -1;
570#endif
Harald Welte0df904d2018-12-03 11:00:04 +0100571 sgs_iface_init(tall_msc_ctx, msc_network);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200572
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200573 rc = vty_read_config_file(msc_cmdline_config.config_file, NULL);
574 if (rc < 0) {
Harald Welte703f2ec2018-01-25 00:36:42 +0100575 LOGP(DMSC, LOGL_FATAL, "Failed to parse the config file: '%s'\n",
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200576 msc_cmdline_config.config_file);
577 return 1;
578 }
579
Neels Hofmeyr80447eb2018-12-05 01:11:28 +0100580 /* Initialize MNCC socket if appropriate. If the cmdline option -M is present, it overrides the .cfg file
581 * setting 'msc' / 'mncc external MNCC_SOCKET_PATH'. Note that when -M is given, it "bleeds" back into the vty
582 * 'write' command and is reflected in the written out 'mncc external' cfg. */
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200583 if (msc_cmdline_config.mncc_sock_path) {
Neels Hofmeyr80447eb2018-12-05 01:11:28 +0100584 LOGP(DMNCC, LOGL_NOTICE,
585 "MNCC socket path is configured from commandline argument -M."
586 " This affects a written-back config file. Instead consider using the config file directly"
587 " ('msc' / 'mncc external MNCC_SOCKET_PATH').\n");
588 gsm_network_set_mncc_sock_path(msc_network, msc_cmdline_config.mncc_sock_path);
589 }
590 if (msc_network->mncc_sock_path) {
Neels Hofmeyrfb153cb2018-12-05 00:47:31 +0100591 msc_network->mncc_recv = mncc_sock_from_cc;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200592 rc = mncc_sock_init(msc_network,
Neels Hofmeyr80447eb2018-12-05 01:11:28 +0100593 msc_network->mncc_sock_path);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200594 if (rc) {
595 fprintf(stderr, "MNCC socket initialization failed. exiting.\n");
596 exit(1);
597 }
598 } else
599 DEBUGP(DMNCC, "Using internal MNCC handler.\n");
600
601 /* start telnet after reading config for vty_get_bind_addr() */
602 rc = telnet_init_dynif(tall_msc_ctx, &msc_network,
603 vty_get_bind_addr(), OSMO_VTY_PORT_MSC);
604 if (rc < 0)
605 return 2;
606
607 /* BSC stuff is to be split behind an A-interface to be used with
608 * OsmoBSC, but there is no need to remove it yet. Most of the
609 * following code until iu_init() is legacy. */
610
611#ifdef BUILD_SMPP
612 smpp_openbsc_start(msc_network);
613#endif
614
615 /* start control interface after reading config for
616 * ctrl_vty_get_bind_addr() */
617 msc_network->ctrl = ctrl_interface_setup_dynip(msc_network, ctrl_vty_get_bind_addr(),
618 OSMO_CTRL_PORT_MSC, NULL);
619 if (!msc_network->ctrl) {
620 printf("Failed to initialize control interface. Exiting.\n");
621 return -1;
622 }
623
624#if 0
625TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_install().
626 if (bsc_base_ctrl_cmds_install() != 0) {
627 printf("Failed to initialize the BSC control commands.\n");
628 return -1;
629 }
630#endif
631
632 if (msc_ctrl_cmds_install(msc_network) != 0) {
633 printf("Failed to initialize the MSC control commands.\n");
634 return -1;
635 }
636
637 /* seed the PRNG */
638 srand(time(NULL));
639 /* TODO: is this used for crypto?? Improve randomness, at least we
640 * should try to use the nanoseconds part of the current time. */
641
642 if (db_init(msc_cmdline_config.database_name)) {
643 printf("DB: Failed to init database: %s\n",
644 msc_cmdline_config.database_name);
645 return 4;
646 }
647
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100648 if (msc_gsup_client_start(msc_network)) {
649 fprintf(stderr, "Failed to start GSUP client\n");
650 exit(1);
651 }
652
653 msc_a_i_t_gsup_init(msc_network);
654
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200655 if (msc_vlr_start(msc_network)) {
656 fprintf(stderr, "Failed to start VLR\n");
657 exit(1);
658 }
659
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200660 if (db_prepare()) {
661 printf("DB: Failed to prepare database.\n");
662 return 5;
663 }
664
665 /* setup the timer */
666 osmo_timer_setup(&db_sync_timer, db_sync_timer_cb, NULL);
667 if (msc_cmdline_config.use_db_counter)
668 osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
669
670 signal(SIGINT, &signal_handler);
Harald Welte28cd9442017-08-20 20:50:06 +0200671 signal(SIGTERM, &signal_handler);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200672 signal(SIGABRT, &signal_handler);
673 signal(SIGUSR1, &signal_handler);
674 signal(SIGUSR2, &signal_handler);
675 osmo_init_ignore_signals();
676
677 /* start the SMS queue */
678 if (sms_queue_start(msc_network, 20) != 0)
679 return -1;
680
Neels Hofmeyr6c8afe12017-09-04 01:03:58 +0200681 msc_network->mgw.client = mgcp_client_init(
682 msc_network, &msc_network->mgw.conf);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200683
Neels Hofmeyr6c8afe12017-09-04 01:03:58 +0200684 if (mgcp_client_connect(msc_network->mgw.client)) {
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200685 printf("MGCPGW connect failed\n");
686 return 7;
687 }
688
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100689 if (ss7_setup(tall_msc_ctx, &sccp_a, &sccp_iu)) {
Philipp Maierfbf66102017-04-09 12:32:51 +0200690 printf("Setting up SCCP client failed.\n");
691 return 8;
692 }
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200693
Vadim Yanitskiy81635d32019-03-22 02:09:06 +0700694 if (sgs_server_open(g_sgs)) {
695 printf("Starting SGs server failed\n");
696 return 9;
697 }
698
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100699 msc_network->a.sri = sccp_ran_init(msc_network, sccp_a, OSMO_SCCP_SSN_BSSAP,
700 "OsmoMSC-A", &msc_ran_infra[OSMO_RAT_GERAN_A],
701 msc_network);
702 if (!msc_network->a.sri) {
703 printf("Setting up A receiver failed\n");
704 return 10;
705 }
706 LOGP(DMSC, LOGL_NOTICE, "A-interface: SCCP user %s, cs7-instance %u (%s)\n",
707 osmo_sccp_user_name(msc_network->a.sri->scu),
708 osmo_sccp_get_ss7(msc_network->a.sri->sccp)->cfg.id,
709 osmo_sccp_get_ss7(msc_network->a.sri->sccp)->cfg.name);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200710
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100711#ifdef BUILD_IU
712 talloc_asn1_ctx = talloc_named_const(tall_msc_ctx, 0, "asn1");
713
714 msc_network->iu.sri = sccp_ran_init(msc_network, sccp_iu, OSMO_SCCP_SSN_RANAP,
715 "OsmoMSC-IuCS", &msc_ran_infra[OSMO_RAT_UTRAN_IU],
716 msc_network);
717 if (!msc_network->iu.sri) {
718 printf("Setting up IuCS receiver failed\n");
719 return 11;
720 }
721
722 /* Compatibility with legacy osmo-hnbgw that was unable to properly handle RESET messages. */
723 msc_network->iu.sri->ignore_missing_reset = true;
724
725 LOGP(DMSC, LOGL_NOTICE, "Iu-interface: SCCP user %s, cs7-instance %u (%s)\n",
726 osmo_sccp_user_name(msc_network->iu.sri->scu),
727 osmo_sccp_get_ss7(msc_network->iu.sri->sccp)->cfg.id,
728 osmo_sccp_get_ss7(msc_network->iu.sri->sccp)->cfg.name);
729#endif
Philipp Maierfbf66102017-04-09 12:32:51 +0200730
Vadim Yanitskiy1f9b0862018-08-04 01:16:52 +0700731 /* Init RRLP handlers */
732 msc_rrlp_init();
733
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200734 if (msc_cmdline_config.daemonize) {
735 rc = osmo_daemonize();
736 if (rc < 0) {
737 perror("Error during daemonize");
738 return 6;
739 }
740 }
741
Pau Espin Pedrolb8744862018-08-13 16:29:50 +0200742 while (!quit) {
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200743 log_reset_context();
744 osmo_select_main(0);
745 }
Pau Espin Pedrolb8744862018-08-13 16:29:50 +0200746
747 msc_network_shutdown(msc_network);
748 osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
749 sleep(3);
750
751 log_fini();
752
753 /**
754 * Report the heap state of root context, then free,
755 * so both ASAN and Valgrind are happy...
756 */
757 talloc_report_full(tall_msc_ctx, stderr);
758 talloc_free(tall_msc_ctx);
759
Vadim Yanitskiyd8d4d8c2018-08-14 19:13:15 +0700760 /* FIXME: VTY code still uses NULL-context */
761 talloc_free(tall_vty_ctx);
762
Pau Espin Pedrolb8744862018-08-13 16:29:50 +0200763 /**
764 * Report the heap state of NULL context, then free,
765 * so both ASAN and Valgrind are happy...
766 */
767 talloc_report_full(NULL, stderr);
768 talloc_disable_null_tracking();
769 return 0;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200770}