blob: 00a6459b6e754815b613280be8e9c5db9bbabb43 [file] [log] [blame]
Harald Welte936f6722016-05-03 18:51:18 +02001/* (C) 2016 by Harald Welte <laforge@gnumonks.org>
2 *
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
Harald Welteaabae9e2016-04-28 12:48:14 +020020#include <signal.h>
Harald Weltee687be52016-05-03 18:49:27 +020021#include <errno.h>
Maxea8b0d42017-02-14 16:53:04 +010022#include <stdbool.h>
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +010023#include <getopt.h>
24
Harald Weltee72cf552016-04-28 07:18:49 +020025#include <osmocom/core/msgb.h>
26#include <osmocom/core/logging.h>
27#include <osmocom/core/application.h>
28#include <osmocom/gsm/gsup.h>
Max2fc63a62016-12-20 16:49:20 +010029#include <osmocom/gsm/apn.h>
Neels Hofmeyr627de842016-12-19 13:16:06 +010030#include <osmocom/gsm/gsm48_ie.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010031#include <osmocom/vty/vty.h>
32#include <osmocom/vty/command.h>
33#include <osmocom/vty/telnet_interface.h>
34#include <osmocom/vty/ports.h>
Max372868b2017-03-02 12:12:00 +010035#include <osmocom/ctrl/control_vty.h>
Harald Weltee72cf552016-04-28 07:18:49 +020036
37#include "db.h"
Maxd4bebbd2017-03-02 12:00:19 +010038#include "hlr.h"
Max372868b2017-03-02 12:12:00 +010039#include "ctrl.h"
Harald Weltee72cf552016-04-28 07:18:49 +020040#include "logging.h"
41#include "gsup_server.h"
Harald Weltee687be52016-05-03 18:49:27 +020042#include "gsup_router.h"
Harald Weltee72cf552016-04-28 07:18:49 +020043#include "rand.h"
Maxea8b0d42017-02-14 16:53:04 +010044#include "luop.h"
Neels Hofmeyr7685a782017-01-30 23:30:26 +010045#include "hlr_vty.h"
Harald Weltee72cf552016-04-28 07:18:49 +020046
Maxd4bebbd2017-03-02 12:00:19 +010047static struct hlr *g_hlr;
Harald Weltee72cf552016-04-28 07:18:49 +020048
Harald Weltee687be52016-05-03 18:49:27 +020049/***********************************************************************
50 * Send Auth Info handling
51 ***********************************************************************/
52
Harald Weltee72cf552016-04-28 07:18:49 +020053/* process an incoming SAI request */
54static int rx_send_auth_info(struct osmo_gsup_conn *conn,
Maxd4bebbd2017-03-02 12:00:19 +010055 const struct osmo_gsup_message *gsup,
56 struct db_context *dbc)
Harald Weltee72cf552016-04-28 07:18:49 +020057{
58 struct osmo_gsup_message gsup_out;
59 struct msgb *msg_out;
60 int rc;
61
62 /* initialize return message structure */
63 memset(&gsup_out, 0, sizeof(gsup_out));
Harald Weltee72cf552016-04-28 07:18:49 +020064 memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));
65
Maxd4bebbd2017-03-02 12:00:19 +010066 rc = db_get_auc(dbc, gsup->imsi, gsup_out.auth_vectors,
Harald Weltee72cf552016-04-28 07:18:49 +020067 ARRAY_SIZE(gsup_out.auth_vectors),
Harald Welte9be0d2f2016-06-10 17:34:02 +020068 gsup->rand, gsup->auts);
Harald Weltecfc752b2016-05-05 16:38:14 +020069 if (rc < 0) {
Harald Weltee72cf552016-04-28 07:18:49 +020070 gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;
Harald Weltecfc752b2016-05-05 16:38:14 +020071 gsup_out.cause = GMM_CAUSE_NET_FAIL;
72 } else if (rc == 0) {
73 gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;
74 gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
Harald Welte15db8262016-05-05 16:50:39 +020075 } else {
76 gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT;
77 gsup_out.num_auth_vectors = rc;
Harald Weltee72cf552016-04-28 07:18:49 +020078 }
79
Harald Weltee687be52016-05-03 18:49:27 +020080 msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
Harald Weltee72cf552016-04-28 07:18:49 +020081 osmo_gsup_encode(msg_out, &gsup_out);
82 return osmo_gsup_conn_send(conn, msg_out);
83}
84
Harald Weltee687be52016-05-03 18:49:27 +020085/***********************************************************************
86 * LU Operation State / Structure
87 ***********************************************************************/
88
89static LLIST_HEAD(g_lu_ops);
90
Harald Weltee687be52016-05-03 18:49:27 +020091/*! Receive Cancel Location Result from old VLR/SGSN */
92void lu_op_rx_cancel_old_ack(struct lu_operation *luop,
Maxea8b0d42017-02-14 16:53:04 +010093 const struct osmo_gsup_message *gsup)
Harald Weltee687be52016-05-03 18:49:27 +020094{
95 OSMO_ASSERT(luop->state == LU_S_CANCEL_SENT);
96 /* FIXME: Check for spoofing */
97
98 osmo_timer_del(&luop->timer);
99
100 /* FIXME */
101
102 lu_op_tx_insert_subscr_data(luop);
103}
104
Harald Weltee687be52016-05-03 18:49:27 +0200105/*! Receive Insert Subscriber Data Result from new VLR/SGSN */
106static void lu_op_rx_insert_subscr_data_ack(struct lu_operation *luop,
107 const struct osmo_gsup_message *gsup)
108{
109 OSMO_ASSERT(luop->state == LU_S_ISD_SENT);
110 /* FIXME: Check for spoofing */
111
112 osmo_timer_del(&luop->timer);
113
114 /* Subscriber_Present_HLR */
115 /* CS only: Check_SS_required? -> MAP-FW-CHECK_SS_IND.req */
116
117 /* Send final ACK towards inquiring VLR/SGSN */
118 lu_op_tx_ack(luop);
119}
120
121/*! Receive GSUP message for given \ref lu_operation */
122void lu_op_rx_gsup(struct lu_operation *luop,
123 const struct osmo_gsup_message *gsup)
124{
125 switch (gsup->message_type) {
126 case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
127 /* FIXME */
128 break;
129 case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
130 lu_op_rx_insert_subscr_data_ack(luop, gsup);
131 break;
132 case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
133 /* FIXME */
134 break;
135 case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:
136 lu_op_rx_cancel_old_ack(luop, gsup);
137 break;
138 default:
139 LOGP(DMAIN, LOGL_ERROR, "Unhandled GSUP msg_type 0x%02x\n",
140 gsup->message_type);
141 break;
142 }
143}
144
Harald Weltee687be52016-05-03 18:49:27 +0200145/*! Receive Update Location Request, creates new \ref lu_operation */
146static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
147 const struct osmo_gsup_message *gsup)
148{
Maxea8b0d42017-02-14 16:53:04 +0100149 struct lu_operation *luop = lu_op_alloc_conn(conn);
150 if (!luop) {
Harald Weltee687be52016-05-03 18:49:27 +0200151 LOGP(DMAIN, LOGL_ERROR, "LU REQ from conn without addr?\n");
Maxea8b0d42017-02-14 16:53:04 +0100152 return -EINVAL;
Harald Weltee687be52016-05-03 18:49:27 +0200153 }
154
Harald Weltee687be52016-05-03 18:49:27 +0200155 lu_op_statechg(luop, LU_S_LU_RECEIVED);
Maxea8b0d42017-02-14 16:53:04 +0100156
Harald Weltee687be52016-05-03 18:49:27 +0200157 if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
158 luop->is_ps = true;
159 llist_add(&luop->list, &g_lu_ops);
160
161 /* Roughly follwing "Process Update_Location_HLR" of TS 09.02 */
162
163 /* check if subscriber is known at all */
Maxd4bebbd2017-03-02 12:00:19 +0100164 if (!lu_op_fill_subscr(luop, g_hlr->dbc, gsup->imsi)) {
Harald Weltee687be52016-05-03 18:49:27 +0200165 /* Send Error back: Subscriber Unknown in HLR */
166 strcpy(luop->subscr.imsi, gsup->imsi);
167 lu_op_tx_error(luop, GMM_CAUSE_IMSI_UNKNOWN);
168 return 0;
169 }
170
Harald Welte99909272016-05-05 18:24:15 +0200171 /* Check if subscriber is generally permitted on CS or PS
172 * service (as requested) */
Maxea8b0d42017-02-14 16:53:04 +0100173 if (!luop->is_ps && !luop->subscr.nam_cs) {
Harald Weltee687be52016-05-03 18:49:27 +0200174 lu_op_tx_error(luop, GMM_CAUSE_PLMN_NOTALLOWED);
175 return 0;
Maxea8b0d42017-02-14 16:53:04 +0100176 } else if (luop->is_ps && !luop->subscr.nam_ps) {
Harald Weltee687be52016-05-03 18:49:27 +0200177 lu_op_tx_error(luop, GMM_CAUSE_GPRS_NOTALLOWED);
178 return 0;
179 }
180
181 /* TODO: Set subscriber tracing = deactive in VLR/SGSN */
182
183#if 0
184 /* Cancel in old VLR/SGSN, if new VLR/SGSN differs from old */
185 if (luop->is_ps == false &&
186 strcmp(subscr->vlr_number, vlr_number)) {
Harald Weltee687be52016-05-03 18:49:27 +0200187 lu_op_tx_cancel_old(luop);
188 } else if (luop->is_ps == true &&
189 strcmp(subscr->sgsn_number, sgsn_number)) {
Harald Weltee687be52016-05-03 18:49:27 +0200190 lu_op_tx_cancel_old(luop);
191 } else
192#endif
193 {
194 /* TODO: Subscriber allowed to roam in PLMN? */
195 /* TODO: Update RoutingInfo */
196 /* TODO: Reset Flag MS Purged (cs/ps) */
197 /* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */
198 lu_op_tx_insert_subscr_data(luop);
199 }
200 return 0;
201}
202
Harald Welteb18f0e02016-05-05 21:03:03 +0200203static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
204 const struct osmo_gsup_message *gsup)
205{
206 struct osmo_gsup_message gsup_reply = {0};
207 struct msgb *msg_out;
208 bool is_ps = false;
209 int rc;
210
211 LOGP(DAUC, LOGL_INFO, "%s: Purge MS (%s)\n", gsup->imsi,
212 is_ps ? "PS" : "CS");
213
214 memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));
215
216 if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
217 is_ps = true;
218
219 /* FIXME: check if the VLR that sends the purge is the same that
220 * we have on record. Only update if yes */
221
222 /* Perform the actual update of the DB */
Maxd4bebbd2017-03-02 12:00:19 +0100223 rc = db_subscr_purge(g_hlr->dbc, gsup->imsi, is_ps);
Harald Welteb18f0e02016-05-05 21:03:03 +0200224
225 if (rc == 1)
226 gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;
227 else if (rc == 0) {
228 gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
229 gsup_reply.cause = GMM_CAUSE_IMSI_UNKNOWN;
230 } else {
231 gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
232 gsup_reply.cause = GMM_CAUSE_NET_FAIL;
233 }
234
235 msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
236 osmo_gsup_encode(msg_out, &gsup_reply);
237 return osmo_gsup_conn_send(conn, msg_out);
238}
239
Harald Weltee72cf552016-04-28 07:18:49 +0200240static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
241{
242 static struct osmo_gsup_message gsup;
243 int rc;
244
Harald Weltee687be52016-05-03 18:49:27 +0200245 rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
Harald Weltee72cf552016-04-28 07:18:49 +0200246 if (rc < 0) {
247 LOGP(DMAIN, LOGL_ERROR, "error in GSUP decode: %d\n", rc);
248 return rc;
249 }
250
251 switch (gsup.message_type) {
252 /* requests sent to us */
253 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
Maxd4bebbd2017-03-02 12:00:19 +0100254 rx_send_auth_info(conn, &gsup, g_hlr->dbc);
Harald Weltee72cf552016-04-28 07:18:49 +0200255 break;
256 case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
Harald Weltee687be52016-05-03 18:49:27 +0200257 rx_upd_loc_req(conn, &gsup);
Harald Weltee72cf552016-04-28 07:18:49 +0200258 break;
Harald Welteb18f0e02016-05-05 21:03:03 +0200259 case OSMO_GSUP_MSGT_PURGE_MS_REQUEST:
260 rx_purge_ms_req(conn, &gsup);
261 break;
Harald Weltee72cf552016-04-28 07:18:49 +0200262 /* responses to requests sent by us */
Max9cacb6f2017-02-20 17:22:56 +0100263 case OSMO_GSUP_MSGT_DELETE_DATA_ERROR:
264 LOGP(DMAIN, LOGL_ERROR, "Error while deleting subscriber data "
265 "for IMSI %s\n", gsup.imsi);
266 break;
267 case OSMO_GSUP_MSGT_DELETE_DATA_RESULT:
268 LOGP(DMAIN, LOGL_ERROR, "Deleting subscriber data for IMSI %s\n",
269 gsup.imsi);
270 break;
Harald Weltee72cf552016-04-28 07:18:49 +0200271 case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
Harald Weltee72cf552016-04-28 07:18:49 +0200272 case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
Harald Weltee687be52016-05-03 18:49:27 +0200273 case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
274 case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:
275 {
Maxea8b0d42017-02-14 16:53:04 +0100276 struct lu_operation *luop = lu_op_by_imsi(gsup.imsi,
277 &g_lu_ops);
Harald Weltee687be52016-05-03 18:49:27 +0200278 if (!luop) {
Maxaa0fefd2017-02-16 12:25:22 +0100279 LOGP(DMAIN, LOGL_ERROR, "GSUP message %s for "
280 "unknown IMSI %s\n",
281 osmo_gsup_message_type_name(gsup.message_type),
Harald Weltee687be52016-05-03 18:49:27 +0200282 gsup.imsi);
283 break;
284 }
285 lu_op_rx_gsup(luop, &gsup);
286 }
Harald Weltee72cf552016-04-28 07:18:49 +0200287 break;
288 default:
Maxaa0fefd2017-02-16 12:25:22 +0100289 LOGP(DMAIN, LOGL_DEBUG, "Unhandled GSUP message type %s\n",
290 osmo_gsup_message_type_name(gsup.message_type));
Harald Weltee72cf552016-04-28 07:18:49 +0200291 break;
292 }
Harald Welte5341b5d2016-04-28 12:48:39 +0200293 msgb_free(msg);
Harald Weltee72cf552016-04-28 07:18:49 +0200294 return 0;
295}
296
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100297static void print_usage()
298{
299 printf("Usage: osmo-hlr\n");
300}
301
302static void print_help()
303{
304 printf(" -h --help This text.\n");
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100305 printf(" -c --config-file filename The config file to use.\n");
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100306 printf(" -l --database db-name The database to use.\n");
307 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM Enable debugging.\n");
308 printf(" -D --daemonize Fork the process into a background daemon.\n");
309 printf(" -s --disable-color Do not print ANSI colors in the log\n");
310 printf(" -T --timestamp Prefix every log line with a timestamp.\n");
311 printf(" -e --log-level number Set a global loglevel.\n");
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100312 printf(" -V --version Print the version of OsmoHLR.\n");
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100313}
314
315static struct {
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100316 const char *config_file;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100317 const char *db_file;
318 bool daemonize;
319} cmdline_opts = {
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100320 .config_file = "osmo-hlr.cfg",
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100321 .db_file = "hlr.db",
322 .daemonize = false,
323};
324
325static void handle_options(int argc, char **argv)
326{
327 while (1) {
328 int option_index = 0, c;
329 static struct option long_options[] = {
330 {"help", 0, 0, 'h'},
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100331 {"config-file", 1, 0, 'c'},
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100332 {"database", 1, 0, 'l'},
333 {"debug", 1, 0, 'd'},
334 {"daemonize", 0, 0, 'D'},
335 {"disable-color", 0, 0, 's'},
336 {"log-level", 1, 0, 'e'},
337 {"timestamp", 0, 0, 'T'},
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100338 {"version", 0, 0, 'V' },
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100339 {0, 0, 0, 0}
340 };
341
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100342 c = getopt_long(argc, argv, "hc:l:d:Dse:TV",
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100343 long_options, &option_index);
344 if (c == -1)
345 break;
346
347 switch (c) {
348 case 'h':
349 print_usage();
350 print_help();
351 exit(0);
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100352 case 'c':
353 cmdline_opts.config_file = optarg;
354 break;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100355 case 'l':
356 cmdline_opts.db_file = optarg;
357 break;
358 case 'd':
359 log_parse_category_mask(osmo_stderr_target, optarg);
360 break;
361 case 'D':
362 cmdline_opts.daemonize = 1;
363 break;
364 case 's':
365 log_set_use_color(osmo_stderr_target, 0);
366 break;
367 case 'e':
368 log_set_log_level(osmo_stderr_target, atoi(optarg));
369 break;
370 case 'T':
371 log_set_print_timestamp(osmo_stderr_target, 1);
372 break;
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100373 case 'V':
374 print_version(1);
375 exit(0);
376 break;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100377 default:
378 /* catch unknown options *as well as* missing arguments. */
379 fprintf(stderr, "Error in command line options. Exiting.\n");
380 exit(-1);
381 break;
382 }
383 }
384}
385
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100386static void *hlr_ctx = NULL;
Harald Welteaabae9e2016-04-28 12:48:14 +0200387
388static void signal_hdlr(int signal)
389{
390 switch (signal) {
391 case SIGINT:
392 LOGP(DMAIN, LOGL_NOTICE, "Terminating due to SIGINT\n");
Maxd4bebbd2017-03-02 12:00:19 +0100393 osmo_gsup_server_destroy(g_hlr->gs);
394 db_close(g_hlr->dbc);
Harald Welteaabae9e2016-04-28 12:48:14 +0200395 log_fini();
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100396 talloc_report_full(hlr_ctx, stderr);
Harald Welteaabae9e2016-04-28 12:48:14 +0200397 exit(0);
398 break;
399 case SIGUSR1:
400 LOGP(DMAIN, LOGL_DEBUG, "Talloc Report due to SIGUSR1\n");
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100401 talloc_report_full(hlr_ctx, stderr);
Harald Welteaabae9e2016-04-28 12:48:14 +0200402 break;
403 }
404}
Harald Weltee72cf552016-04-28 07:18:49 +0200405
Max372868b2017-03-02 12:12:00 +0100406static const char vlr_copyright[] =
407 "Copyright (C) 2016, 2017 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
408 "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
409 "This is free software: you are free to change and redistribute it.\r\n"
410 "There is NO WARRANTY, to the extent permitted by law.\r\n";
411
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100412static struct vty_app_info vty_info = {
413 .name = "OsmoHLR",
414 .version = PACKAGE_VERSION,
Max372868b2017-03-02 12:12:00 +0100415 .copyright = vlr_copyright,
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100416 .is_config_node = hlr_vty_is_config_node,
417};
418
Harald Weltee72cf552016-04-28 07:18:49 +0200419int main(int argc, char **argv)
420{
Harald Weltee72cf552016-04-28 07:18:49 +0200421 int rc;
422
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100423 hlr_ctx = talloc_named_const(NULL, 1, "OsmoHLR");
424 msgb_talloc_ctx_init(hlr_ctx, 0);
Harald Welteaabae9e2016-04-28 12:48:14 +0200425
Maxd4bebbd2017-03-02 12:00:19 +0100426 g_hlr = talloc_zero(hlr_ctx, struct hlr);
427
Harald Weltee72cf552016-04-28 07:18:49 +0200428 rc = osmo_init_logging(&hlr_log_info);
429 if (rc < 0) {
430 fprintf(stderr, "Error initializing logging\n");
431 exit(1);
432 }
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100433
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100434 vty_init(&vty_info);
Max372868b2017-03-02 12:12:00 +0100435 ctrl_vty_init(hlr_ctx);
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100436 handle_options(argc, argv);
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100437 hlr_vty_init(&hlr_log_info);
438
439 rc = vty_read_config_file(cmdline_opts.config_file, NULL);
440 if (rc < 0) {
441 LOGP(DMAIN, LOGL_FATAL,
442 "Failed to parse the config file: '%s'\n",
443 cmdline_opts.config_file);
444 return rc;
445 }
446
447 /* start telnet after reading config for vty_get_bind_addr() */
448 rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(),
449 OSMO_VTY_PORT_HLR);
450 if (rc < 0)
451 return rc;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100452
Harald Weltee72cf552016-04-28 07:18:49 +0200453 LOGP(DMAIN, LOGL_NOTICE, "hlr starting\n");
454
455 rc = rand_init();
456 if (rc < 0) {
457 LOGP(DMAIN, LOGL_FATAL, "Error initializing random source\n");
458 exit(1);
459 }
460
Maxd4bebbd2017-03-02 12:00:19 +0100461 g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file);
462 if (!g_hlr->dbc) {
Harald Weltee72cf552016-04-28 07:18:49 +0200463 LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");
464 exit(1);
465 }
466
Max9cacb6f2017-02-20 17:22:56 +0100467 g_hlr->gs = osmo_gsup_server_create(hlr_ctx, NULL, 2222, read_cb,
468 &g_lu_ops);
Maxd4bebbd2017-03-02 12:00:19 +0100469 if (!g_hlr->gs) {
Harald Weltee72cf552016-04-28 07:18:49 +0200470 LOGP(DMAIN, LOGL_FATAL, "Error starting GSUP server\n");
471 exit(1);
472 }
473
Max372868b2017-03-02 12:12:00 +0100474 g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
475 g_hlr->ctrl = hlr_controlif_setup(g_hlr, g_hlr->gs);
476
Harald Welteaabae9e2016-04-28 12:48:14 +0200477 osmo_init_ignore_signals();
478 signal(SIGINT, &signal_hdlr);
479 signal(SIGUSR1, &signal_hdlr);
480
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100481 if (cmdline_opts.daemonize) {
482 rc = osmo_daemonize();
483 if (rc < 0) {
484 perror("Error during daemonize");
485 exit(1);
486 }
487 }
Harald Welteaabae9e2016-04-28 12:48:14 +0200488
Harald Weltee72cf552016-04-28 07:18:49 +0200489 while (1) {
490 osmo_select_main(0);
491 }
492
Maxd4bebbd2017-03-02 12:00:19 +0100493 db_close(g_hlr->dbc);
Harald Weltee72cf552016-04-28 07:18:49 +0200494
495 log_fini();
496
497 exit(0);
498}